From d7dd7061d2486562f9ba2b8cb224b7e7f17397b5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 04:11:22 +0000 Subject: [PATCH 1/2] Initial plan From e3cfc79240b620b0a542e9a48f475d943191b7f8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 04:21:48 +0000 Subject: [PATCH 2/2] fix: allow multiple assign_to_agent for same issue when pull_request_repo differs When assign_to_agent is called twice for the same issue with different pull_request_repo values, the second assignment was silently skipped because the already-assigned guard only checked whether the agent was already in the assignees list. Fix: treat the pair of (agent, pull_request_repo) as the uniqueness key. When no pull_request_repo is specified, the existing dedup behaviour is preserved. When a pull_request_repo is explicitly provided, the assignment proceeds even if the agent is already assigned, so that Copilot can be triggered for a second target repository (e.g. Android after iOS). Adds a test to validate both the new behaviour and that the original dedup behaviour is unchanged. Fixes #6588 Agent-Logs-Url: https://github.com/github/gh-aw/sessions/e8d9b238-ae61-49b3-b0b3-df1d3a3bfa94 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/assign_to_agent.cjs | 7 ++- actions/setup/js/assign_to_agent.test.cjs | 61 +++++++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/actions/setup/js/assign_to_agent.cjs b/actions/setup/js/assign_to_agent.cjs index 7ba14123c30..8391286bd8e 100644 --- a/actions/setup/js/assign_to_agent.cjs +++ b/actions/setup/js/assign_to_agent.cjs @@ -448,8 +448,11 @@ async function main() { core.info(`${type} ID: ${assignableId}`); - // Check if agent is already assigned - if (currentAssignees.some(a => a.id === agentId)) { + // Check if agent is already assigned. + // When a pull_request_repo is explicitly provided, the pair of (agent, pull_request_repo) + // is the uniqueness key, so we allow the assignment to proceed even if the agent is + // already assigned (it may target a different repository). + if (currentAssignees.some(a => a.id === agentId) && !effectivePullRequestRepoId) { core.info(`${agentName} is already assigned to ${type} #${number}`); results.push({ issue_number: issueNumber, diff --git a/actions/setup/js/assign_to_agent.test.cjs b/actions/setup/js/assign_to_agent.test.cjs index da6068095f5..6749f7a4d62 100644 --- a/actions/setup/js/assign_to_agent.test.cjs +++ b/actions/setup/js/assign_to_agent.test.cjs @@ -344,6 +344,67 @@ describe("assign_to_agent", () => { expect(mockCore.info).toHaveBeenCalledWith(expect.stringContaining("copilot is already assigned to issue #42")); }); + it("should allow assignment when agent is already assigned but pull_request_repo differs", async () => { + // When an agent is already assigned to an issue but a different pull_request_repo is requested, + // the assignment must proceed so that Copilot is triggered for the new target repository. + process.env.GH_AW_AGENT_ALLOWED_PULL_REQUEST_REPOS = "test-owner/android-repo"; + setAgentOutput({ + items: [ + { + type: "assign_to_agent", + issue_number: 42, + agent: "copilot", + pull_request_repo: "test-owner/android-repo", + }, + ], + errors: [], + }); + + // Mock GraphQL responses - agent is already assigned, but a different pull_request_repo is provided + mockGithub.graphql + // Get item PR repository ID + .mockResolvedValueOnce({ + repository: { + id: "android-repo-id", + }, + }) + // Find agent + .mockResolvedValueOnce({ + repository: { + suggestedActors: { + nodes: [{ login: "copilot-swe-agent", id: "MDQ6VXNlcjE=" }], + }, + }, + }) + // Get issue details - agent already assigned + .mockResolvedValueOnce({ + repository: { + issue: { + id: "issue-id", + assignees: { + nodes: [{ id: "MDQ6VXNlcjE=" }], + }, + }, + }, + }) + // Assign agent with agentAssignment (targetRepositoryId = android-repo-id) + .mockResolvedValueOnce({ + replaceActorsForAssignable: { + __typename: "ReplaceActorsForAssignablePayload", + }, + }); + + await eval(`(async () => { ${assignToAgentScript}; await main(); })()`); + + // Should NOT skip the assignment + expect(mockCore.info).not.toHaveBeenCalledWith(expect.stringContaining("copilot is already assigned to issue #42")); + // Should proceed with the assignment + expect(mockCore.info).toHaveBeenCalledWith(expect.stringContaining("Successfully assigned copilot coding agent to issue #42")); + // The mutation must include the target repository ID for the new platform + const lastGraphQLCall = mockGithub.graphql.mock.lastCall; + expect(lastGraphQLCall[1].targetRepoId).toBe("android-repo-id"); + }); + it("should handle API errors gracefully", async () => { setAgentOutput({ items: [