From b6faac8bfd5037ffd503fe4c8d4bd2da93154372 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Jun 2026 23:55:52 +0000 Subject: [PATCH 1/8] Surface assign-to-agent failures in agent failure reporting Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/assign_to_agent.cjs | 17 ++++- actions/setup/js/assign_to_agent.test.cjs | 2 + actions/setup/js/handle_agent_failure.cjs | 72 ++++++++++--------- .../setup/js/handle_agent_failure.test.cjs | 30 +++++++- 4 files changed, 84 insertions(+), 37 deletions(-) diff --git a/actions/setup/js/assign_to_agent.cjs b/actions/setup/js/assign_to_agent.cjs index 9263ec31db2..1a9e905eb92 100644 --- a/actions/setup/js/assign_to_agent.cjs +++ b/actions/setup/js/assign_to_agent.cjs @@ -399,7 +399,17 @@ async function main(config = {}) { const errorType = isAuthError ? "authentication/permission" : "agent availability"; core.warning(`Agent assignment failed for ${agentName} on ${type} #${number} due to ${errorType} error. Skipping due to ignore-if-error=true.`); core.info(`Error details: ${errorMessage}`); - _allResults.push({ issue_number: issueNumber, pull_number: pullNumber, agent: agentName, owner: effectiveOwner, repo: effectiveRepo, pull_request_repo: effectivePullRequestRepoSlug, success: true, skipped: true }); + _allResults.push({ + issue_number: issueNumber, + pull_number: pullNumber, + agent: agentName, + owner: effectiveOwner, + repo: effectiveRepo, + pull_request_repo: effectivePullRequestRepoSlug, + success: true, + skipped: true, + error: errorMessage, + }); return { success: true, skipped: true }; } @@ -451,12 +461,13 @@ function getAssignToAgentAssigned() { /** * Returns the "assignment_errors" output string for step outputs. - * Format: "issue:N:agent:error" or "pr:N:agent:error" per failure, newline-separated. + * Format: "issue:N:agent:error" or "pr:N:agent:error" per failure/skipped-with-error, + * newline-separated. * @returns {string} */ function getAssignToAgentErrors() { return _allResults - .filter(r => !r.success && !r.skipped) + .filter(r => r.error && (!r.success || r.skipped)) .map(r => { const number = r.issue_number || r.pull_number; const prefix = r.issue_number ? "issue" : "pr"; diff --git a/actions/setup/js/assign_to_agent.test.cjs b/actions/setup/js/assign_to_agent.test.cjs index d2ae930db8f..1c9b80e84f2 100644 --- a/actions/setup/js/assign_to_agent.test.cjs +++ b/actions/setup/js/assign_to_agent.test.cjs @@ -1054,6 +1054,8 @@ describe("assign_to_agent", () => { // Should not fail the workflow expect(mockCore.setFailed).not.toHaveBeenCalled(); + expect(mockCore.setOutput).toHaveBeenCalledWith("assignment_error_count", "0"); + expect(mockCore.setOutput).toHaveBeenCalledWith("assignment_errors", expect.stringContaining("Bad credentials")); // Summary should show skipped assignments expect(mockCore.summary.addRaw).toHaveBeenCalled(); diff --git a/actions/setup/js/handle_agent_failure.cjs b/actions/setup/js/handle_agent_failure.cjs index 08d45e45dd0..18f3d19b22a 100644 --- a/actions/setup/js/handle_agent_failure.cjs +++ b/actions/setup/js/handle_agent_failure.cjs @@ -2030,6 +2030,41 @@ function buildCredentialAuthErrorContext(auditJsonlPathOverride) { const templatePath = getPromptPath("credential_auth_error.md"); return "\n" + renderTemplateFromFile(templatePath, { providers: providersList }); } + +/** + * Build a context string when assign_to_agent reported assignment errors. + * Includes remediation guidance for token and Copilot access setup. + * @param {boolean} hasAssignmentErrors + * @param {string} assignmentErrors + * @returns {string} + */ +function buildAssignmentErrorsContext(hasAssignmentErrors, assignmentErrors) { + if (!hasAssignmentErrors || !assignmentErrors) { + return ""; + } + + let context = buildWarningAlertLine("Agent Assignment Failed", "Failed to assign agent to issues or pull requests."); + context += "\n**Assignment Errors:**\n"; + + const errorLines = assignmentErrors.split("\n").filter(line => line.trim()); + for (const errorLine of errorLines) { + const parts = errorLine.split(":"); + if (parts.length >= 4) { + const type = parts[0]; // "issue" or "pr" + const number = parts[1]; + const agent = parts[2]; + const error = parts.slice(3).join(":"); + context += `- ${type === "issue" ? "Issue" : "PR"} #${number} (agent: ${agent}): ${error}\n`; + } + } + + context += "\nTo resolve this, verify the agent token and Copilot access configuration:\n"; + context += "- Configure a valid `GH_AW_AGENT_TOKEN` with repository write access and active Copilot entitlement\n"; + context += "- If your org supports it, add `permissions: { copilot-requests: write }` to use org inference without a personal token\n"; + context += "- Docs: https://github.github.com/gh-aw/reference/engines/#github-copilot-default\n\n"; + + return context; +} /** * Build a context string when assigning the Copilot coding agent to created issues failed. * @param {boolean} hasAssignCopilotFailures - Whether any copilot assignments failed @@ -2700,7 +2735,7 @@ async function main() { const isTimedOut = agentConclusion === "timed_out" || agenticEngineTimeout; // Check if there are assignment errors (regardless of agent job status) - const hasAssignmentErrors = parseInt(assignmentErrorCount, 10) > 0; + const hasAssignmentErrors = parseInt(assignmentErrorCount, 10) > 0 || assignmentErrors.split("\n").some(line => line.trim()); // Check if there are copilot assignment failures for created issues (regardless of agent job status) const hasAssignCopilotFailures = parseInt(assignCopilotFailureCount, 10) > 0; @@ -3061,22 +3096,7 @@ async function main() { const runId = extractRunId(runUrl); // Build assignment errors context - let assignmentErrorsContext = ""; - if (hasAssignmentErrors && assignmentErrors) { - assignmentErrorsContext = buildWarningAlertLine("Agent Assignment Failed", "Failed to assign agent to issues due to insufficient permissions or missing token.") + "\n**Assignment Errors:**\n"; - const errorLines = assignmentErrors.split("\n").filter(line => line.trim()); - for (const errorLine of errorLines) { - const parts = errorLine.split(":"); - if (parts.length >= 4) { - const type = parts[0]; // "issue" or "pr" - const number = parts[1]; - const agent = parts[2]; - const error = parts.slice(3).join(":"); // Rest is the error message - assignmentErrorsContext += `- ${type === "issue" ? "Issue" : "PR"} #${number} (agent: ${agent}): ${error}\n`; - } - } - assignmentErrorsContext += "\n"; - } + const assignmentErrorsContext = buildAssignmentErrorsContext(hasAssignmentErrors, assignmentErrors); // Build create_discussion errors context const createDiscussionErrorsContext = hasCreateDiscussionErrors ? buildCreateDiscussionErrorsContext(createDiscussionErrors) : ""; @@ -3284,22 +3304,7 @@ async function main() { const issueTemplate = fs.readFileSync(issueTemplatePath, "utf8"); // Build assignment errors context - let assignmentErrorsContext = ""; - if (hasAssignmentErrors && assignmentErrors) { - assignmentErrorsContext = buildWarningAlertLine("Agent Assignment Failed", "Failed to assign agent to issues due to insufficient permissions or missing token.") + "\n**Assignment Errors:**\n"; - const errorLines = assignmentErrors.split("\n").filter(line => line.trim()); - for (const errorLine of errorLines) { - const parts = errorLine.split(":"); - if (parts.length >= 4) { - const type = parts[0]; // "issue" or "pr" - const number = parts[1]; - const agent = parts[2]; - const error = parts.slice(3).join(":"); // Rest is the error message - assignmentErrorsContext += `- ${type === "issue" ? "Issue" : "PR"} #${number} (agent: ${agent}): ${error}\n`; - } - } - assignmentErrorsContext += "\n"; - } + const assignmentErrorsContext = buildAssignmentErrorsContext(hasAssignmentErrors, assignmentErrors); // Build create_discussion errors context const createDiscussionErrorsContext = hasCreateDiscussionErrors ? buildCreateDiscussionErrorsContext(createDiscussionErrors) : ""; @@ -3531,6 +3536,7 @@ module.exports = { loadToolDenialsExceededEvents, buildToolDenialsExceededContext, buildCredentialAuthErrorContext, + buildAssignmentErrorsContext, buildAICreditsRateLimitErrorContext, buildUnknownModelAICreditsContext, hasEngineMaxRunsExceededSignal, diff --git a/actions/setup/js/handle_agent_failure.test.cjs b/actions/setup/js/handle_agent_failure.test.cjs index 372b10297e5..2407219cd1f 100644 --- a/actions/setup/js/handle_agent_failure.test.cjs +++ b/actions/setup/js/handle_agent_failure.test.cjs @@ -12,6 +12,7 @@ describe("handle_agent_failure", () => { let buildReportIncompleteContext; let buildFailureIssueTitle; let buildSecretVerificationContext; + let buildAssignmentErrorsContext; let getActionFailureIssueExpiresHours; const ENGINE_RATE_LIMIT_TEMPLATE = "> [!WARNING]\n> **Engine Rate Limited (HTTP 429)**\n> OTLP telemetry\n> {engine_label}\n"; const ENGINE_MAX_RUNS_EXCEEDED_TEMPLATE = "> [!WARNING]\n> **Engine Max Runs Exceeded**\n> max-runs guardrail\n> {engine_label}\n"; @@ -31,7 +32,16 @@ describe("handle_agent_failure", () => { // Reset module registry so each test gets a fresh require vi.resetModules(); - ({ main, buildCodePushFailureContext, buildPushRepoMemoryFailureContext, buildReportIncompleteContext, buildFailureIssueTitle, buildSecretVerificationContext, getActionFailureIssueExpiresHours } = require("./handle_agent_failure.cjs")); + ({ + main, + buildCodePushFailureContext, + buildPushRepoMemoryFailureContext, + buildReportIncompleteContext, + buildFailureIssueTitle, + buildSecretVerificationContext, + buildAssignmentErrorsContext, + getActionFailureIssueExpiresHours, + } = require("./handle_agent_failure.cjs")); }); afterEach(() => { @@ -1311,6 +1321,24 @@ describe("handle_agent_failure", () => { expect(buildSecretVerificationContext("", "")).toBe(""); }); + describe("buildAssignmentErrorsContext", () => { + it("returns empty string when there are no assignment errors", () => { + expect(buildAssignmentErrorsContext(false, "")).toBe(""); + expect(buildAssignmentErrorsContext(true, "")).toBe(""); + }); + + it("renders assignment failures with token guidance docs", () => { + const result = buildAssignmentErrorsContext(true, "issue:42:copilot:Bad credentials\npr:7:copilot:copilot coding agent is not available for this repository"); + + expect(result).toContain("Agent Assignment Failed"); + expect(result).toContain("Issue #42 (agent: copilot): Bad credentials"); + expect(result).toContain("PR #7 (agent: copilot): copilot coding agent is not available for this repository"); + expect(result).toContain("GH_AW_AGENT_TOKEN"); + expect(result).toContain("copilot-requests: write"); + expect(result).toContain("https://github.github.com/gh-aw/reference/engines/#github-copilot-default"); + }); + }); + it("returns generic warning for non-copilot engines when verification failed", () => { const result = buildSecretVerificationContext("failed", "claude"); expect(result).toContain("Secret Verification Failed"); From 9f2d97ce1570b9006d4659f6764dafdf7cb7f92f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Jun 2026 23:57:48 +0000 Subject: [PATCH 2/8] Refine assignment failure propagation and guidance Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/assign_to_agent.cjs | 20 ++++++++++++-------- actions/setup/js/handle_agent_failure.cjs | 6 ++++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/actions/setup/js/assign_to_agent.cjs b/actions/setup/js/assign_to_agent.cjs index 1a9e905eb92..044e4444979 100644 --- a/actions/setup/js/assign_to_agent.cjs +++ b/actions/setup/js/assign_to_agent.cjs @@ -466,14 +466,18 @@ function getAssignToAgentAssigned() { * @returns {string} */ function getAssignToAgentErrors() { - return _allResults - .filter(r => r.error && (!r.success || r.skipped)) - .map(r => { - const number = r.issue_number || r.pull_number; - const prefix = r.issue_number ? "issue" : "pr"; - return `${prefix}:${number}:${r.agent}:${r.error}`; - }) - .join("\n"); + return ( + _allResults + // Include skipped(ignore-if-error) entries that still captured an error so + // downstream failure handling can surface assignment problems in issue/comment reports. + .filter(r => r.error && (!r.success || r.skipped)) + .map(r => { + const number = r.issue_number || r.pull_number; + const prefix = r.issue_number ? "issue" : "pr"; + return `${prefix}:${number}:${r.agent}:${r.error}`; + }) + .join("\n") + ); } /** diff --git a/actions/setup/js/handle_agent_failure.cjs b/actions/setup/js/handle_agent_failure.cjs index 18f3d19b22a..2da23d6ecd0 100644 --- a/actions/setup/js/handle_agent_failure.cjs +++ b/actions/setup/js/handle_agent_failure.cjs @@ -2734,8 +2734,10 @@ async function main() { // in the engine output and sets the agentic_engine_timeout output. const isTimedOut = agentConclusion === "timed_out" || agenticEngineTimeout; - // Check if there are assignment errors (regardless of agent job status) - const hasAssignmentErrors = parseInt(assignmentErrorCount, 10) > 0 || assignmentErrors.split("\n").some(line => line.trim()); + // Check if there are assignment errors (regardless of agent job status). + // Use assignment_errors as the single source of truth because it includes + // both hard failures and skipped(ignore-if-error) assignment errors. + const hasAssignmentErrors = assignmentErrors.split("\n").some(line => line.trim()); // Check if there are copilot assignment failures for created issues (regardless of agent job status) const hasAssignCopilotFailures = parseInt(assignCopilotFailureCount, 10) > 0; From 9e2832904244d3f5763303624bfbab916909b950 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Jun 2026 23:59:53 +0000 Subject: [PATCH 3/8] Clarify assignment error detection and token scope guidance Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/assign_to_agent.cjs | 2 +- actions/setup/js/handle_agent_failure.cjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/actions/setup/js/assign_to_agent.cjs b/actions/setup/js/assign_to_agent.cjs index 044e4444979..b67c17495a0 100644 --- a/actions/setup/js/assign_to_agent.cjs +++ b/actions/setup/js/assign_to_agent.cjs @@ -470,7 +470,7 @@ function getAssignToAgentErrors() { _allResults // Include skipped(ignore-if-error) entries that still captured an error so // downstream failure handling can surface assignment problems in issue/comment reports. - .filter(r => r.error && (!r.success || r.skipped)) + .filter(r => r.error && (!r.success || (r.success && r.skipped))) .map(r => { const number = r.issue_number || r.pull_number; const prefix = r.issue_number ? "issue" : "pr"; diff --git a/actions/setup/js/handle_agent_failure.cjs b/actions/setup/js/handle_agent_failure.cjs index 2da23d6ecd0..9e7a8278010 100644 --- a/actions/setup/js/handle_agent_failure.cjs +++ b/actions/setup/js/handle_agent_failure.cjs @@ -2059,7 +2059,7 @@ function buildAssignmentErrorsContext(hasAssignmentErrors, assignmentErrors) { } context += "\nTo resolve this, verify the agent token and Copilot access configuration:\n"; - context += "- Configure a valid `GH_AW_AGENT_TOKEN` with repository write access and active Copilot entitlement\n"; + context += "- Configure a valid `GH_AW_AGENT_TOKEN` with `issues: write` (and `pull-requests: write` when assigning PRs) plus active Copilot entitlement\n"; context += "- If your org supports it, add `permissions: { copilot-requests: write }` to use org inference without a personal token\n"; context += "- Docs: https://github.github.com/gh-aw/reference/engines/#github-copilot-default\n\n"; From 0f82872baec12098b035c44a8c4bc983ccf5e0be Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Jun 2026 00:01:46 +0000 Subject: [PATCH 4/8] Polish assignment error filter and guidance text Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/assign_to_agent.cjs | 2 +- actions/setup/js/handle_agent_failure.cjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/actions/setup/js/assign_to_agent.cjs b/actions/setup/js/assign_to_agent.cjs index b67c17495a0..044e4444979 100644 --- a/actions/setup/js/assign_to_agent.cjs +++ b/actions/setup/js/assign_to_agent.cjs @@ -470,7 +470,7 @@ function getAssignToAgentErrors() { _allResults // Include skipped(ignore-if-error) entries that still captured an error so // downstream failure handling can surface assignment problems in issue/comment reports. - .filter(r => r.error && (!r.success || (r.success && r.skipped))) + .filter(r => r.error && (!r.success || r.skipped)) .map(r => { const number = r.issue_number || r.pull_number; const prefix = r.issue_number ? "issue" : "pr"; diff --git a/actions/setup/js/handle_agent_failure.cjs b/actions/setup/js/handle_agent_failure.cjs index 9e7a8278010..05aaae03ccf 100644 --- a/actions/setup/js/handle_agent_failure.cjs +++ b/actions/setup/js/handle_agent_failure.cjs @@ -2059,7 +2059,7 @@ function buildAssignmentErrorsContext(hasAssignmentErrors, assignmentErrors) { } context += "\nTo resolve this, verify the agent token and Copilot access configuration:\n"; - context += "- Configure a valid `GH_AW_AGENT_TOKEN` with `issues: write` (and `pull-requests: write` when assigning PRs) plus active Copilot entitlement\n"; + context += "- Configure a valid `GH_AW_AGENT_TOKEN` with `issues: write` and `pull-requests: write` permissions plus active Copilot entitlement\n"; context += "- If your org supports it, add `permissions: { copilot-requests: write }` to use org inference without a personal token\n"; context += "- Docs: https://github.github.com/gh-aw/reference/engines/#github-copilot-default\n\n"; From f15ef620846702a1d0cd26e31b14632cd4dd6416 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Jun 2026 00:03:39 +0000 Subject: [PATCH 5/8] Adjust assignment error filter and permission wording Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/assign_to_agent.cjs | 2 +- actions/setup/js/handle_agent_failure.cjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/actions/setup/js/assign_to_agent.cjs b/actions/setup/js/assign_to_agent.cjs index 044e4444979..b67c17495a0 100644 --- a/actions/setup/js/assign_to_agent.cjs +++ b/actions/setup/js/assign_to_agent.cjs @@ -470,7 +470,7 @@ function getAssignToAgentErrors() { _allResults // Include skipped(ignore-if-error) entries that still captured an error so // downstream failure handling can surface assignment problems in issue/comment reports. - .filter(r => r.error && (!r.success || r.skipped)) + .filter(r => r.error && (!r.success || (r.success && r.skipped))) .map(r => { const number = r.issue_number || r.pull_number; const prefix = r.issue_number ? "issue" : "pr"; diff --git a/actions/setup/js/handle_agent_failure.cjs b/actions/setup/js/handle_agent_failure.cjs index 05aaae03ccf..deb0db6dc21 100644 --- a/actions/setup/js/handle_agent_failure.cjs +++ b/actions/setup/js/handle_agent_failure.cjs @@ -2059,7 +2059,7 @@ function buildAssignmentErrorsContext(hasAssignmentErrors, assignmentErrors) { } context += "\nTo resolve this, verify the agent token and Copilot access configuration:\n"; - context += "- Configure a valid `GH_AW_AGENT_TOKEN` with `issues: write` and `pull-requests: write` permissions plus active Copilot entitlement\n"; + context += "- Configure a valid `GH_AW_AGENT_TOKEN` with issue/PR write access plus active Copilot entitlement\n"; context += "- If your org supports it, add `permissions: { copilot-requests: write }` to use org inference without a personal token\n"; context += "- Docs: https://github.github.com/gh-aw/reference/engines/#github-copilot-default\n\n"; From c3b8209e49bc754c20d65aaa91a77c07ef4d02e7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Jun 2026 00:05:25 +0000 Subject: [PATCH 6/8] Simplify assignment error filter expression Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/assign_to_agent.cjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/setup/js/assign_to_agent.cjs b/actions/setup/js/assign_to_agent.cjs index b67c17495a0..b61c654b28b 100644 --- a/actions/setup/js/assign_to_agent.cjs +++ b/actions/setup/js/assign_to_agent.cjs @@ -470,7 +470,7 @@ function getAssignToAgentErrors() { _allResults // Include skipped(ignore-if-error) entries that still captured an error so // downstream failure handling can surface assignment problems in issue/comment reports. - .filter(r => r.error && (!r.success || (r.success && r.skipped))) + .filter(r => r.error && (r.skipped || !r.success)) .map(r => { const number = r.issue_number || r.pull_number; const prefix = r.issue_number ? "issue" : "pr"; From a83172e3c2c3cb202286ffb91692ff7847a4f1cc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Jun 2026 00:07:34 +0000 Subject: [PATCH 7/8] Refine assignment context helper and messaging clarity Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/assign_to_agent.cjs | 1 + actions/setup/js/handle_agent_failure.cjs | 11 +++++------ actions/setup/js/handle_agent_failure.test.cjs | 5 ++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/actions/setup/js/assign_to_agent.cjs b/actions/setup/js/assign_to_agent.cjs index b61c654b28b..1e415fc9c8e 100644 --- a/actions/setup/js/assign_to_agent.cjs +++ b/actions/setup/js/assign_to_agent.cjs @@ -470,6 +470,7 @@ function getAssignToAgentErrors() { _allResults // Include skipped(ignore-if-error) entries that still captured an error so // downstream failure handling can surface assignment problems in issue/comment reports. + // Include hard failures (!success) and ignored failures (skipped=true with error). .filter(r => r.error && (r.skipped || !r.success)) .map(r => { const number = r.issue_number || r.pull_number; diff --git a/actions/setup/js/handle_agent_failure.cjs b/actions/setup/js/handle_agent_failure.cjs index deb0db6dc21..ef999241820 100644 --- a/actions/setup/js/handle_agent_failure.cjs +++ b/actions/setup/js/handle_agent_failure.cjs @@ -2034,12 +2034,11 @@ function buildCredentialAuthErrorContext(auditJsonlPathOverride) { /** * Build a context string when assign_to_agent reported assignment errors. * Includes remediation guidance for token and Copilot access setup. - * @param {boolean} hasAssignmentErrors * @param {string} assignmentErrors * @returns {string} */ -function buildAssignmentErrorsContext(hasAssignmentErrors, assignmentErrors) { - if (!hasAssignmentErrors || !assignmentErrors) { +function buildAssignmentErrorsContext(assignmentErrors) { + if (!assignmentErrors) { return ""; } @@ -2059,7 +2058,7 @@ function buildAssignmentErrorsContext(hasAssignmentErrors, assignmentErrors) { } context += "\nTo resolve this, verify the agent token and Copilot access configuration:\n"; - context += "- Configure a valid `GH_AW_AGENT_TOKEN` with issue/PR write access plus active Copilot entitlement\n"; + context += "- Configure a valid `GH_AW_AGENT_TOKEN` with `issues: write` and `pull_requests: write` plus active Copilot entitlement\n"; context += "- If your org supports it, add `permissions: { copilot-requests: write }` to use org inference without a personal token\n"; context += "- Docs: https://github.github.com/gh-aw/reference/engines/#github-copilot-default\n\n"; @@ -3098,7 +3097,7 @@ async function main() { const runId = extractRunId(runUrl); // Build assignment errors context - const assignmentErrorsContext = buildAssignmentErrorsContext(hasAssignmentErrors, assignmentErrors); + const assignmentErrorsContext = buildAssignmentErrorsContext(assignmentErrors); // Build create_discussion errors context const createDiscussionErrorsContext = hasCreateDiscussionErrors ? buildCreateDiscussionErrorsContext(createDiscussionErrors) : ""; @@ -3306,7 +3305,7 @@ async function main() { const issueTemplate = fs.readFileSync(issueTemplatePath, "utf8"); // Build assignment errors context - const assignmentErrorsContext = buildAssignmentErrorsContext(hasAssignmentErrors, assignmentErrors); + const assignmentErrorsContext = buildAssignmentErrorsContext(assignmentErrors); // Build create_discussion errors context const createDiscussionErrorsContext = hasCreateDiscussionErrors ? buildCreateDiscussionErrorsContext(createDiscussionErrors) : ""; diff --git a/actions/setup/js/handle_agent_failure.test.cjs b/actions/setup/js/handle_agent_failure.test.cjs index 2407219cd1f..781e74693c9 100644 --- a/actions/setup/js/handle_agent_failure.test.cjs +++ b/actions/setup/js/handle_agent_failure.test.cjs @@ -1323,12 +1323,11 @@ describe("handle_agent_failure", () => { describe("buildAssignmentErrorsContext", () => { it("returns empty string when there are no assignment errors", () => { - expect(buildAssignmentErrorsContext(false, "")).toBe(""); - expect(buildAssignmentErrorsContext(true, "")).toBe(""); + expect(buildAssignmentErrorsContext("")).toBe(""); }); it("renders assignment failures with token guidance docs", () => { - const result = buildAssignmentErrorsContext(true, "issue:42:copilot:Bad credentials\npr:7:copilot:copilot coding agent is not available for this repository"); + const result = buildAssignmentErrorsContext("issue:42:copilot:Bad credentials\npr:7:copilot:copilot coding agent is not available for this repository"); expect(result).toContain("Agent Assignment Failed"); expect(result).toContain("Issue #42 (agent: copilot): Bad credentials"); From fac0a36c4be52c086b0465647ee054962b79c708 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Jun 2026 04:19:56 +0000 Subject: [PATCH 8/8] fix: use hyphenated pull-requests permission name and guard whitespace-only assignmentErrors Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/handle_agent_failure.cjs | 4 ++-- actions/setup/js/handle_agent_failure.test.cjs | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/actions/setup/js/handle_agent_failure.cjs b/actions/setup/js/handle_agent_failure.cjs index ef999241820..c71ad6a8c72 100644 --- a/actions/setup/js/handle_agent_failure.cjs +++ b/actions/setup/js/handle_agent_failure.cjs @@ -2038,7 +2038,7 @@ function buildCredentialAuthErrorContext(auditJsonlPathOverride) { * @returns {string} */ function buildAssignmentErrorsContext(assignmentErrors) { - if (!assignmentErrors) { + if (!assignmentErrors || !assignmentErrors.trim()) { return ""; } @@ -2058,7 +2058,7 @@ function buildAssignmentErrorsContext(assignmentErrors) { } context += "\nTo resolve this, verify the agent token and Copilot access configuration:\n"; - context += "- Configure a valid `GH_AW_AGENT_TOKEN` with `issues: write` and `pull_requests: write` plus active Copilot entitlement\n"; + context += "- Configure a valid `GH_AW_AGENT_TOKEN` with `issues: write` and `pull-requests: write` plus active Copilot entitlement\n"; context += "- If your org supports it, add `permissions: { copilot-requests: write }` to use org inference without a personal token\n"; context += "- Docs: https://github.github.com/gh-aw/reference/engines/#github-copilot-default\n\n"; diff --git a/actions/setup/js/handle_agent_failure.test.cjs b/actions/setup/js/handle_agent_failure.test.cjs index 781e74693c9..1278d212261 100644 --- a/actions/setup/js/handle_agent_failure.test.cjs +++ b/actions/setup/js/handle_agent_failure.test.cjs @@ -1326,6 +1326,12 @@ describe("handle_agent_failure", () => { expect(buildAssignmentErrorsContext("")).toBe(""); }); + it("returns empty string for whitespace-only input", () => { + expect(buildAssignmentErrorsContext(" ")).toBe(""); + expect(buildAssignmentErrorsContext("\n")).toBe(""); + expect(buildAssignmentErrorsContext("\n\n")).toBe(""); + }); + it("renders assignment failures with token guidance docs", () => { const result = buildAssignmentErrorsContext("issue:42:copilot:Bad credentials\npr:7:copilot:copilot coding agent is not available for this repository");