From 428f90b00451544bf52588060e3fac2709d7475b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 13:10:45 +0000 Subject: [PATCH 1/3] Initial plan From a44653eff7263c9b93a45328eb65c85cb5c87b37 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 13:30:10 +0000 Subject: [PATCH 2/3] Add ignore-if-missing field to assign-to-agent safe output Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/assign_agent_helpers.cjs | 13 ++ actions/setup/js/assign_to_agent.cjs | 58 +++++++-- actions/setup/js/assign_to_agent.test.cjs | 116 ++++++++++++++++++ .../setup/js/types/safe-outputs-config.d.ts | 1 + pkg/parser/schemas/main_workflow_schema.json | 5 + pkg/workflow/assign_to_agent.go | 5 +- .../compiler_safe_outputs_specialized.go | 5 + 7 files changed, 193 insertions(+), 10 deletions(-) diff --git a/actions/setup/js/assign_agent_helpers.cjs b/actions/setup/js/assign_agent_helpers.cjs index 26e7666d2ff..24e314a197c 100644 --- a/actions/setup/js/assign_agent_helpers.cjs +++ b/actions/setup/js/assign_agent_helpers.cjs @@ -122,6 +122,19 @@ async function findAgent(owner, repo, agentName) { } catch (error) { const errorMessage = getErrorMessage(error); core.error(`Failed to find ${agentName} agent: ${errorMessage}`); + + // Re-throw authentication/permission errors so they can be handled by the caller + // This allows ignore-if-missing logic to work properly + if ( + errorMessage.includes("Bad credentials") || + errorMessage.includes("Not Authenticated") || + errorMessage.includes("Resource not accessible") || + errorMessage.includes("Insufficient permissions") || + errorMessage.includes("requires authentication") + ) { + throw error; + } + return null; } } diff --git a/actions/setup/js/assign_to_agent.cjs b/actions/setup/js/assign_to_agent.cjs index e3d79d26e1e..2f7b762e6af 100644 --- a/actions/setup/js/assign_to_agent.cjs +++ b/actions/setup/js/assign_to_agent.cjs @@ -50,6 +50,12 @@ async function main() { const targetConfig = process.env.GH_AW_AGENT_TARGET?.trim() || "triggering"; core.info(`Target configuration: ${targetConfig}`); + // Get ignore-if-missing flag (defaults to false) + const ignoreIfMissing = process.env.GH_AW_AGENT_IGNORE_IF_MISSING === "true"; + if (ignoreIfMissing) { + core.info("Ignore-if-missing mode enabled: Will not fail if agent token is unavailable"); + } + // Get allowed agents list (comma-separated) const allowedAgentsEnv = process.env.GH_AW_AGENT_ALLOWED?.trim(); const allowedAgents = allowedAgentsEnv @@ -264,6 +270,29 @@ async function main() { }); } catch (error) { let errorMessage = getErrorMessage(error); + + // Check if this is a token authentication error + const isAuthError = + errorMessage.includes("Bad credentials") || + errorMessage.includes("Not Authenticated") || + errorMessage.includes("Resource not accessible") || + errorMessage.includes("Insufficient permissions") || + errorMessage.includes("requires authentication"); + + // If ignore-if-missing is enabled and this is an auth error, log warning and skip + if (ignoreIfMissing && isAuthError) { + core.warning(`Agent token not available or insufficient permissions for assigning ${agentName} to ${type} #${number}. Skipping due to ignore-if-missing=true.`); + core.info(`Error details: ${errorMessage}`); + results.push({ + issue_number: issueNumber, + pull_number: pullNumber, + agent: agentName, + success: true, // Treat as success when ignored + skipped: true, + }); + continue; + } + if (errorMessage.includes("coding agent is not available for this repository")) { // Enrich with available agent logins to aid troubleshooting - uses built-in github object try { @@ -287,15 +316,16 @@ async function main() { } // Generate step summary - const successCount = results.filter(r => r.success).length; - const failureCount = results.length - successCount; + const successCount = results.filter(r => r.success && !r.skipped).length; + const skippedCount = results.filter(r => r.skipped).length; + const failureCount = results.length - successCount - skippedCount; let summaryContent = "## Agent Assignment\n\n"; if (successCount > 0) { summaryContent += `✅ Successfully assigned ${successCount} agent(s):\n\n`; summaryContent += results - .filter(r => r.success) + .filter(r => r.success && !r.skipped) .map(r => { const itemType = r.issue_number ? `Issue #${r.issue_number}` : `Pull Request #${r.pull_number}`; return `- ${itemType} → Agent: ${r.agent}`; @@ -304,10 +334,22 @@ async function main() { summaryContent += "\n\n"; } + if (skippedCount > 0) { + summaryContent += `⏭️ Skipped ${skippedCount} agent assignment(s) (ignore-if-missing enabled):\n\n`; + summaryContent += results + .filter(r => r.skipped) + .map(r => { + const itemType = r.issue_number ? `Issue #${r.issue_number}` : `Pull Request #${r.pull_number}`; + return `- ${itemType} → Agent: ${r.agent} (agent token not available)`; + }) + .join("\n"); + summaryContent += "\n\n"; + } + if (failureCount > 0) { summaryContent += `❌ Failed to assign ${failureCount} agent(s):\n\n`; summaryContent += results - .filter(r => !r.success) + .filter(r => !r.success && !r.skipped) .map(r => { const itemType = r.issue_number ? `Issue #${r.issue_number}` : `Pull Request #${r.pull_number}`; return `- ${itemType} → Agent: ${r.agent}: ${r.error}`; @@ -315,7 +357,7 @@ async function main() { .join("\n"); // Check if any failures were permission-related - const hasPermissionError = results.some(r => (!r.success && r.error?.includes("Resource not accessible")) || r.error?.includes("Insufficient permissions")); + const hasPermissionError = results.some(r => (!r.success && !r.skipped && r.error?.includes("Resource not accessible")) || r.error?.includes("Insufficient permissions")); if (hasPermissionError) { summaryContent += generatePermissionErrorSummary(); @@ -326,7 +368,7 @@ async function main() { // Set outputs const assignedAgents = results - .filter(r => r.success) + .filter(r => r.success && !r.skipped) .map(r => { const number = r.issue_number || r.pull_number; const prefix = r.issue_number ? "issue" : "pr"; @@ -337,7 +379,7 @@ async function main() { // Set assignment error output for failed assignments const assignmentErrors = results - .filter(r => !r.success) + .filter(r => !r.success && !r.skipped) .map(r => { const number = r.issue_number || r.pull_number; const prefix = r.issue_number ? "issue" : "pr"; @@ -347,7 +389,7 @@ async function main() { core.setOutput("assignment_errors", assignmentErrors); core.setOutput("assignment_error_count", failureCount.toString()); - // Fail if any assignments failed + // Fail if any assignments failed (but not if they were skipped) if (failureCount > 0) { core.setFailed(`Failed to assign ${failureCount} agent(s)`); } diff --git a/actions/setup/js/assign_to_agent.test.cjs b/actions/setup/js/assign_to_agent.test.cjs index 1191550e34d..d07c187ab63 100644 --- a/actions/setup/js/assign_to_agent.test.cjs +++ b/actions/setup/js/assign_to_agent.test.cjs @@ -43,6 +43,10 @@ describe("assign_to_agent", () => { beforeEach(() => { vi.clearAllMocks(); + + // Reset mockGithub.graphql to ensure no lingering mock implementations + mockGithub.graphql = vi.fn(); + delete process.env.GH_AW_AGENT_OUTPUT; delete process.env.GH_AW_SAFE_OUTPUTS_STAGED; delete process.env.GH_AW_AGENT_DEFAULT; @@ -50,6 +54,7 @@ describe("assign_to_agent", () => { delete process.env.GH_AW_AGENT_TARGET; delete process.env.GH_AW_AGENT_ALLOWED; delete process.env.GH_AW_TARGET_REPO; + delete process.env.GH_AW_AGENT_IGNORE_IF_MISSING; // Reset context to default mockContext.eventName = "issues"; @@ -806,4 +811,115 @@ describe("assign_to_agent", () => { expect(mockCore.error).not.toHaveBeenCalled(); expect(mockCore.setFailed).not.toHaveBeenCalled(); }); + + it("should skip assignment and not fail when ignore-if-missing is true and token is missing", async () => { + process.env.GH_AW_AGENT_IGNORE_IF_MISSING = "true"; + setAgentOutput({ + items: [ + { + type: "assign_to_agent", + issue_number: 42, + agent: "copilot", + }, + ], + errors: [], + }); + + // Simulate authentication error - use mockRejectedValueOnce to avoid affecting other tests + const authError = new Error("Bad credentials"); + mockGithub.graphql.mockRejectedValueOnce(authError); + + await eval(`(async () => { ${assignToAgentScript}; await main(); })()`); + + // Should log that ignore-if-missing is enabled + expect(mockCore.info).toHaveBeenCalledWith(expect.stringContaining("Ignore-if-missing mode enabled")); + + // Should warn about skipping but not fail + expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("Agent token not available")); + expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("ignore-if-missing=true")); + + // Should not fail the workflow + expect(mockCore.setFailed).not.toHaveBeenCalled(); + + // Summary should show skipped assignments + expect(mockCore.summary.addRaw).toHaveBeenCalled(); + const summaryCall = mockCore.summary.addRaw.mock.calls[0][0]; + expect(summaryCall).toContain("⏭️ Skipped"); + expect(summaryCall).toContain("agent token not available"); + }); + + it("should fail when ignore-if-missing is false (default) and token is missing", async () => { + // Don't set GH_AW_AGENT_IGNORE_IF_MISSING (defaults to false) + setAgentOutput({ + items: [ + { + type: "assign_to_agent", + issue_number: 42, + agent: "copilot", + }, + ], + errors: [], + }); + + // Simulate authentication error + const authError = new Error("Bad credentials"); + mockGithub.graphql.mockRejectedValue(authError); + + await eval(`(async () => { ${assignToAgentScript}; await main(); })()`); + + // Should NOT log ignore-if-missing mode + expect(mockCore.info).not.toHaveBeenCalledWith(expect.stringContaining("Ignore-if-missing mode enabled")); + + // Should error and fail + expect(mockCore.error).toHaveBeenCalledWith(expect.stringContaining("Failed to assign agent")); + expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("Failed to assign 1 agent(s)")); + }); + + it("should handle ignore-if-missing with 'Resource not accessible' error", async () => { + process.env.GH_AW_AGENT_IGNORE_IF_MISSING = "true"; + setAgentOutput({ + items: [ + { + type: "assign_to_agent", + issue_number: 42, + agent: "copilot", + }, + ], + errors: [], + }); + + // Simulate permission error + const permError = new Error("Resource not accessible by integration"); + mockGithub.graphql.mockRejectedValue(permError); + + await eval(`(async () => { ${assignToAgentScript}; await main(); })()`); + + // Should skip and not fail + expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("Agent token not available")); + expect(mockCore.setFailed).not.toHaveBeenCalled(); + }); + + it("should still fail on non-auth errors even with ignore-if-missing enabled", async () => { + process.env.GH_AW_AGENT_IGNORE_IF_MISSING = "true"; + setAgentOutput({ + items: [ + { + type: "assign_to_agent", + issue_number: 42, + agent: "copilot", + }, + ], + errors: [], + }); + + // Simulate a different error (not auth-related) + const otherError = new Error("Network timeout"); + mockGithub.graphql.mockRejectedValue(otherError); + + await eval(`(async () => { ${assignToAgentScript}; await main(); })()`); + + // Should error and fail (not skipped because it's not an auth error) + expect(mockCore.error).toHaveBeenCalledWith(expect.stringContaining("Failed to assign agent")); + expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("Failed to assign 1 agent(s)")); + }); }); diff --git a/actions/setup/js/types/safe-outputs-config.d.ts b/actions/setup/js/types/safe-outputs-config.d.ts index 9148908ca21..95ed76b1619 100644 --- a/actions/setup/js/types/safe-outputs-config.d.ts +++ b/actions/setup/js/types/safe-outputs-config.d.ts @@ -182,6 +182,7 @@ interface AssignToAgentConfig extends SafeOutputConfig { "default-agent"?: string; target?: string; "target-repo"?: string; + "ignore-if-missing"?: boolean; } /** diff --git a/pkg/parser/schemas/main_workflow_schema.json b/pkg/parser/schemas/main_workflow_schema.json index 23c1ea32126..acf40e3e8e8 100644 --- a/pkg/parser/schemas/main_workflow_schema.json +++ b/pkg/parser/schemas/main_workflow_schema.json @@ -4903,6 +4903,11 @@ "type": "string", "description": "Target repository in format 'owner/repo' for cross-repository agent assignment. Takes precedence over trial target repo settings." }, + "ignore-if-missing": { + "type": "boolean", + "description": "If true, the workflow continues gracefully when the agent token (GH_AW_AGENT_TOKEN) is not available, logging a warning instead of failing. Default is false. Useful for workflows that should not fail when agent assignment is optional.", + "default": false + }, "github-token": { "$ref": "#/$defs/github_token", "description": "GitHub token to use for this specific output type. Overrides global github-token if specified." diff --git a/pkg/workflow/assign_to_agent.go b/pkg/workflow/assign_to_agent.go index eafd3d1af20..0270b2469f6 100644 --- a/pkg/workflow/assign_to_agent.go +++ b/pkg/workflow/assign_to_agent.go @@ -10,8 +10,9 @@ var assignToAgentLog = logger.New("workflow:assign_to_agent") type AssignToAgentConfig struct { BaseSafeOutputConfig `yaml:",inline"` SafeOutputTargetConfig `yaml:",inline"` - DefaultAgent string `yaml:"name,omitempty"` // Default agent to assign (e.g., "copilot") - Allowed []string `yaml:"allowed,omitempty"` // Optional list of allowed agent names. If omitted, any agents are allowed. + DefaultAgent string `yaml:"name,omitempty"` // Default agent to assign (e.g., "copilot") + Allowed []string `yaml:"allowed,omitempty"` // Optional list of allowed agent names. If omitted, any agents are allowed. + IgnoreIfMissing bool `yaml:"ignore-if-missing,omitempty"` // If true, workflow continues when agent token is not available } // parseAssignToAgentConfig handles assign-to-agent configuration diff --git a/pkg/workflow/compiler_safe_outputs_specialized.go b/pkg/workflow/compiler_safe_outputs_specialized.go index 7f63477b0c0..28dd86bffdb 100644 --- a/pkg/workflow/compiler_safe_outputs_specialized.go +++ b/pkg/workflow/compiler_safe_outputs_specialized.go @@ -38,6 +38,11 @@ func (c *Compiler) buildAssignToAgentStepConfig(data *WorkflowData, mainJobName customEnvVars = append(customEnvVars, fmt.Sprintf(" GH_AW_AGENT_ALLOWED: %q\n", allowedStr)) } + // Add ignore-if-missing flag if set + if cfg.IgnoreIfMissing { + customEnvVars = append(customEnvVars, " GH_AW_AGENT_IGNORE_IF_MISSING: \"true\"\n") + } + condition := BuildSafeOutputType("assign_to_agent") return SafeOutputStepConfig{ From 4f510e187284f52389adf2a5adcab4dddb763626 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 13:54:17 +0000 Subject: [PATCH 3/3] Rename ignore-if-missing to ignore-if-error Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/assign_to_agent.cjs | 18 +++++------ actions/setup/js/assign_to_agent.test.cjs | 30 +++++++++---------- .../setup/js/types/safe-outputs-config.d.ts | 2 +- pkg/parser/schemas/main_workflow_schema.json | 4 +-- pkg/workflow/assign_to_agent.go | 6 ++-- .../compiler_safe_outputs_specialized.go | 6 ++-- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/actions/setup/js/assign_to_agent.cjs b/actions/setup/js/assign_to_agent.cjs index 2f7b762e6af..0f6384d7c07 100644 --- a/actions/setup/js/assign_to_agent.cjs +++ b/actions/setup/js/assign_to_agent.cjs @@ -50,10 +50,10 @@ async function main() { const targetConfig = process.env.GH_AW_AGENT_TARGET?.trim() || "triggering"; core.info(`Target configuration: ${targetConfig}`); - // Get ignore-if-missing flag (defaults to false) - const ignoreIfMissing = process.env.GH_AW_AGENT_IGNORE_IF_MISSING === "true"; - if (ignoreIfMissing) { - core.info("Ignore-if-missing mode enabled: Will not fail if agent token is unavailable"); + // Get ignore-if-error flag (defaults to false) + const ignoreIfError = process.env.GH_AW_AGENT_IGNORE_IF_ERROR === "true"; + if (ignoreIfError) { + core.info("Ignore-if-error mode enabled: Will not fail if agent assignment encounters errors"); } // Get allowed agents list (comma-separated) @@ -279,9 +279,9 @@ async function main() { errorMessage.includes("Insufficient permissions") || errorMessage.includes("requires authentication"); - // If ignore-if-missing is enabled and this is an auth error, log warning and skip - if (ignoreIfMissing && isAuthError) { - core.warning(`Agent token not available or insufficient permissions for assigning ${agentName} to ${type} #${number}. Skipping due to ignore-if-missing=true.`); + // If ignore-if-error is enabled and this is an auth error, log warning and skip + if (ignoreIfError && isAuthError) { + core.warning(`Agent assignment failed for ${agentName} on ${type} #${number} due to authentication/permission error. Skipping due to ignore-if-error=true.`); core.info(`Error details: ${errorMessage}`); results.push({ issue_number: issueNumber, @@ -335,12 +335,12 @@ async function main() { } if (skippedCount > 0) { - summaryContent += `⏭️ Skipped ${skippedCount} agent assignment(s) (ignore-if-missing enabled):\n\n`; + summaryContent += `⏭️ Skipped ${skippedCount} agent assignment(s) (ignore-if-error enabled):\n\n`; summaryContent += results .filter(r => r.skipped) .map(r => { const itemType = r.issue_number ? `Issue #${r.issue_number}` : `Pull Request #${r.pull_number}`; - return `- ${itemType} → Agent: ${r.agent} (agent token not available)`; + return `- ${itemType} → Agent: ${r.agent} (assignment failed due to error)`; }) .join("\n"); summaryContent += "\n\n"; diff --git a/actions/setup/js/assign_to_agent.test.cjs b/actions/setup/js/assign_to_agent.test.cjs index d07c187ab63..05a75d51b2b 100644 --- a/actions/setup/js/assign_to_agent.test.cjs +++ b/actions/setup/js/assign_to_agent.test.cjs @@ -54,7 +54,7 @@ describe("assign_to_agent", () => { delete process.env.GH_AW_AGENT_TARGET; delete process.env.GH_AW_AGENT_ALLOWED; delete process.env.GH_AW_TARGET_REPO; - delete process.env.GH_AW_AGENT_IGNORE_IF_MISSING; + delete process.env.GH_AW_AGENT_IGNORE_IF_ERROR; // Reset context to default mockContext.eventName = "issues"; @@ -812,8 +812,8 @@ describe("assign_to_agent", () => { expect(mockCore.setFailed).not.toHaveBeenCalled(); }); - it("should skip assignment and not fail when ignore-if-missing is true and token is missing", async () => { - process.env.GH_AW_AGENT_IGNORE_IF_MISSING = "true"; + it("should skip assignment and not fail when ignore-if-error is true and auth error occurs", async () => { + process.env.GH_AW_AGENT_IGNORE_IF_ERROR = "true"; setAgentOutput({ items: [ { @@ -831,12 +831,12 @@ describe("assign_to_agent", () => { await eval(`(async () => { ${assignToAgentScript}; await main(); })()`); - // Should log that ignore-if-missing is enabled - expect(mockCore.info).toHaveBeenCalledWith(expect.stringContaining("Ignore-if-missing mode enabled")); + // Should log that ignore-if-error is enabled + expect(mockCore.info).toHaveBeenCalledWith(expect.stringContaining("Ignore-if-error mode enabled: Will not fail if agent assignment encounters errors")); // Should warn about skipping but not fail - expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("Agent token not available")); - expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("ignore-if-missing=true")); + expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("Agent assignment failed")); + expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("ignore-if-error=true")); // Should not fail the workflow expect(mockCore.setFailed).not.toHaveBeenCalled(); @@ -845,10 +845,10 @@ describe("assign_to_agent", () => { expect(mockCore.summary.addRaw).toHaveBeenCalled(); const summaryCall = mockCore.summary.addRaw.mock.calls[0][0]; expect(summaryCall).toContain("⏭️ Skipped"); - expect(summaryCall).toContain("agent token not available"); + expect(summaryCall).toContain("assignment failed due to error"); }); - it("should fail when ignore-if-missing is false (default) and token is missing", async () => { + it("should fail when ignore-if-error is false (default) and auth error occurs", async () => { // Don't set GH_AW_AGENT_IGNORE_IF_MISSING (defaults to false) setAgentOutput({ items: [ @@ -867,16 +867,16 @@ describe("assign_to_agent", () => { await eval(`(async () => { ${assignToAgentScript}; await main(); })()`); - // Should NOT log ignore-if-missing mode - expect(mockCore.info).not.toHaveBeenCalledWith(expect.stringContaining("Ignore-if-missing mode enabled")); + // Should NOT log ignore-if-error mode + expect(mockCore.info).not.toHaveBeenCalledWith(expect.stringContaining("ignore-if-error mode enabled")); // Should error and fail expect(mockCore.error).toHaveBeenCalledWith(expect.stringContaining("Failed to assign agent")); expect(mockCore.setFailed).toHaveBeenCalledWith(expect.stringContaining("Failed to assign 1 agent(s)")); }); - it("should handle ignore-if-missing with 'Resource not accessible' error", async () => { - process.env.GH_AW_AGENT_IGNORE_IF_MISSING = "true"; + it("should handle ignore-if-error when 'Resource not accessible' error", async () => { + process.env.GH_AW_AGENT_IGNORE_IF_ERROR = "true"; setAgentOutput({ items: [ { @@ -895,11 +895,11 @@ describe("assign_to_agent", () => { await eval(`(async () => { ${assignToAgentScript}; await main(); })()`); // Should skip and not fail - expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("Agent token not available")); + expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("Agent assignment failed")); expect(mockCore.setFailed).not.toHaveBeenCalled(); }); - it("should still fail on non-auth errors even with ignore-if-missing enabled", async () => { + it("should still fail on non-auth errors even with ignore-if-error enabled", async () => { process.env.GH_AW_AGENT_IGNORE_IF_MISSING = "true"; setAgentOutput({ items: [ diff --git a/actions/setup/js/types/safe-outputs-config.d.ts b/actions/setup/js/types/safe-outputs-config.d.ts index 95ed76b1619..f1eb310512b 100644 --- a/actions/setup/js/types/safe-outputs-config.d.ts +++ b/actions/setup/js/types/safe-outputs-config.d.ts @@ -182,7 +182,7 @@ interface AssignToAgentConfig extends SafeOutputConfig { "default-agent"?: string; target?: string; "target-repo"?: string; - "ignore-if-missing"?: boolean; + "ignore-if-error"?: boolean; } /** diff --git a/pkg/parser/schemas/main_workflow_schema.json b/pkg/parser/schemas/main_workflow_schema.json index acf40e3e8e8..82001886207 100644 --- a/pkg/parser/schemas/main_workflow_schema.json +++ b/pkg/parser/schemas/main_workflow_schema.json @@ -4903,9 +4903,9 @@ "type": "string", "description": "Target repository in format 'owner/repo' for cross-repository agent assignment. Takes precedence over trial target repo settings." }, - "ignore-if-missing": { + "ignore-if-error": { "type": "boolean", - "description": "If true, the workflow continues gracefully when the agent token (GH_AW_AGENT_TOKEN) is not available, logging a warning instead of failing. Default is false. Useful for workflows that should not fail when agent assignment is optional.", + "description": "If true, the workflow continues gracefully when agent assignment fails (e.g., due to missing token or insufficient permissions), logging a warning instead of failing. Default is false. Useful for workflows that should not fail when agent assignment is optional.", "default": false }, "github-token": { diff --git a/pkg/workflow/assign_to_agent.go b/pkg/workflow/assign_to_agent.go index 0270b2469f6..743f3d2a3bc 100644 --- a/pkg/workflow/assign_to_agent.go +++ b/pkg/workflow/assign_to_agent.go @@ -10,9 +10,9 @@ var assignToAgentLog = logger.New("workflow:assign_to_agent") type AssignToAgentConfig struct { BaseSafeOutputConfig `yaml:",inline"` SafeOutputTargetConfig `yaml:",inline"` - DefaultAgent string `yaml:"name,omitempty"` // Default agent to assign (e.g., "copilot") - Allowed []string `yaml:"allowed,omitempty"` // Optional list of allowed agent names. If omitted, any agents are allowed. - IgnoreIfMissing bool `yaml:"ignore-if-missing,omitempty"` // If true, workflow continues when agent token is not available + DefaultAgent string `yaml:"name,omitempty"` // Default agent to assign (e.g., "copilot") + Allowed []string `yaml:"allowed,omitempty"` // Optional list of allowed agent names. If omitted, any agents are allowed. + IgnoreIfError bool `yaml:"ignore-if-error,omitempty"` // If true, workflow continues when agent assignment fails } // parseAssignToAgentConfig handles assign-to-agent configuration diff --git a/pkg/workflow/compiler_safe_outputs_specialized.go b/pkg/workflow/compiler_safe_outputs_specialized.go index 28dd86bffdb..f4743255a37 100644 --- a/pkg/workflow/compiler_safe_outputs_specialized.go +++ b/pkg/workflow/compiler_safe_outputs_specialized.go @@ -38,9 +38,9 @@ func (c *Compiler) buildAssignToAgentStepConfig(data *WorkflowData, mainJobName customEnvVars = append(customEnvVars, fmt.Sprintf(" GH_AW_AGENT_ALLOWED: %q\n", allowedStr)) } - // Add ignore-if-missing flag if set - if cfg.IgnoreIfMissing { - customEnvVars = append(customEnvVars, " GH_AW_AGENT_IGNORE_IF_MISSING: \"true\"\n") + // Add ignore-if-error flag if set + if cfg.IgnoreIfError { + customEnvVars = append(customEnvVars, " GH_AW_AGENT_IGNORE_IF_ERROR: \"true\"\n") } condition := BuildSafeOutputType("assign_to_agent")