Skip to content

Commit a3d1daa

Browse files
authored
Let user select which github remote to target coding agent sessions against (#7645)
* Let user select which github remote to target coding agent sessions against * update test
1 parent bdb29c2 commit a3d1daa

File tree

5 files changed

+88
-6
lines changed

5 files changed

+88
-6
lines changed

package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1740,6 +1740,17 @@
17401740
"icon": "$(refresh)",
17411741
"category": "%command.pull.request.category%"
17421742
},
1743+
{
1744+
"command": "pr.preferredCodingAgentGitHubRemote",
1745+
"title": "%command.pr.preferredCodingAgentGitHubRemote.title%",
1746+
"icon": "$(gear)",
1747+
"category": "%command.pull.request.category%"
1748+
},
1749+
{
1750+
"command": "pr.resetCodingAgentPreferences",
1751+
"title": "%command.pr.resetCodingAgentPreferences.title%",
1752+
"category": "%command.pull.request.category%"
1753+
},
17431754
{
17441755
"command": "pr.closeChatSessionPullRequest",
17451756
"title": "%command.pr.closeChatSessionPullRequest.title%",
@@ -2653,6 +2664,11 @@
26532664
"command": "pr.refreshChatSessions",
26542665
"when": "view == workbench.view.chat.sessions.copilot-swe-agent",
26552666
"group": "navigation@1"
2667+
},
2668+
{
2669+
"command": "pr.preferredCodingAgentGitHubRemote",
2670+
"when": "view == workbench.view.chat.sessions.copilot-swe-agent",
2671+
"group": "navigation@1"
26562672
}
26572673
],
26582674
"view/item/context": [

package.nls.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,8 @@
322322
"command.notification.chatSummarizeNotification.title": "Summarize With Copilot",
323323
"command.codingAgent.openSessionLog.title": "Open Coding Agent Session Log",
324324
"command.pr.closeChatSessionPullRequest.title": "Close Pull Request",
325+
"command.pr.preferredCodingAgentGitHubRemote.title": "Set Preferred GitHub Remote for Coding Agent Sessions",
326+
"command.pr.resetCodingAgentPreferences.title": "Reset Coding Agent Workspace Preferences",
325327
"command.pr.cancelCodingAgent.title": "Cancel Coding Agent",
326328
"welcome.github.login.contents": {
327329
"message": "You have not yet signed in with GitHub\n[Sign in](command:pr.signin)",

src/commands.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,4 +1903,16 @@ ${contents}
19031903
copilotRemoteAgentManager.refreshChatSessions();
19041904
})
19051905
);
1906+
1907+
context.subscriptions.push(
1908+
vscode.commands.registerCommand('pr.preferredCodingAgentGitHubRemote', async () => {
1909+
await copilotRemoteAgentManager.promptAndUpdatePreferredGitHubRemote();
1910+
})
1911+
);
1912+
1913+
context.subscriptions.push(
1914+
vscode.commands.registerCommand('pr.resetCodingAgentPreferences', async () => {
1915+
await copilotRemoteAgentManager.resetCodingAgentPreferences();
1916+
})
1917+
);
19061918
}

src/github/copilotRemoteAgent.ts

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ const COPILOT = '@copilot';
4444

4545
const body_suffix = vscode.l10n.t('Created from VS Code via the [GitHub Pull Request](https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-pull-request-github) extension.');
4646

47+
const PREFERRED_GITHUB_CODING_AGENT_REMOTE_WORKSPACE_KEY = 'PREFERRED_GITHUB_CODING_AGENT_REMOTE';
48+
4749
export class CopilotRemoteAgentManager extends Disposable {
4850
public static ID = 'CopilotRemoteAgentManager';
4951

@@ -209,23 +211,72 @@ export class CopilotRemoteAgentManager extends Disposable {
209211
);
210212
}
211213

214+
public async resetCodingAgentPreferences() {
215+
await this.context.workspaceState.update(PREFERRED_GITHUB_CODING_AGENT_REMOTE_WORKSPACE_KEY, undefined);
216+
}
217+
218+
public async promptAndUpdatePreferredGitHubRemote(skipIfValueAlreadyCached = false): Promise<GitHubRemote | undefined> {
219+
if (skipIfValueAlreadyCached) {
220+
const cachedValue = await this.context.workspaceState.get(PREFERRED_GITHUB_CODING_AGENT_REMOTE_WORKSPACE_KEY);
221+
if (cachedValue) {
222+
return;
223+
}
224+
}
225+
226+
const fm = this.firstFolderManager();
227+
if (!fm) {
228+
return;
229+
}
230+
231+
const ghRemotes = await fm.getAllGitHubRemotes();
232+
Logger.trace(`There are ${ghRemotes.length} GitHub remotes available to select from`, CopilotRemoteAgentManager.ID);
233+
if (!ghRemotes || ghRemotes.length === 0) {
234+
return;
235+
}
236+
237+
const result = await chooseItem<GitHubRemote>(
238+
ghRemotes,
239+
itemValue => `${itemValue.remoteName} (${itemValue.owner}/${itemValue.repositoryName})`,
240+
{
241+
title: vscode.l10n.t('Set the GitHub remote to target when creating a coding agent session'),
242+
}
243+
);
244+
245+
if (!result) {
246+
Logger.warn('No coding agent GitHub remote selected. Clearing preferences.', CopilotRemoteAgentManager.ID);
247+
return;
248+
}
249+
250+
Logger.appendLine(`Updated '${result.remoteName}' as preferred coding agent remote`, CopilotRemoteAgentManager.ID);
251+
await this.context.workspaceState.update(PREFERRED_GITHUB_CODING_AGENT_REMOTE_WORKSPACE_KEY, result.remoteName);
252+
return result;
253+
}
254+
212255
async repoInfo(fm?: FolderRepositoryManager): Promise<RepoInfo | undefined> {
213256
fm = fm || this.firstFolderManager();
214257
const repository = fm?.repository;
215258
const ghRepository = fm?.gitHubRepositories.find(repo => repo.remote instanceof GitHubRemote) as GitHubRepository | undefined;
216259
if (!fm || !repository || !ghRepository) {
217260
return;
218261
}
219-
220262
const baseRef = repository.state.HEAD?.name; // TODO: Consider edge cases
263+
const preferredRemoteName = this.context.workspaceState.get(PREFERRED_GITHUB_CODING_AGENT_REMOTE_WORKSPACE_KEY);
221264
const ghRemotes = await fm.getGitHubRemotes();
222265
if (!ghRemotes || ghRemotes.length === 0) {
223266
return;
224267
}
225268

226269
const remote =
227-
ghRemotes.find(remote => remote.remoteName === 'origin')
228-
|| ghRemotes[0]; // Fallback to the first remote
270+
preferredRemoteName
271+
? ghRemotes.find(remote => remote.remoteName === preferredRemoteName) // Cached preferred value
272+
: (ghRemotes.find(remote => remote.remoteName === 'origin') || ghRemotes[0]); // Fallback to the first remote
273+
274+
if (!remote) {
275+
Logger.error(`no valid remotes for coding agent`, CopilotRemoteAgentManager.ID);
276+
// Clear preference, something is wrong
277+
this.context.workspaceState.update(PREFERRED_GITHUB_CODING_AGENT_REMOTE_WORKSPACE_KEY, undefined);
278+
return;
279+
}
229280

230281
// Extract repo data from target remote
231282
const { owner, repositoryName: repo } = remote;
@@ -462,6 +513,10 @@ export class CopilotRemoteAgentManager extends Disposable {
462513
return { error: vscode.l10n.t('Failed to initialize Copilot API'), state: 'error' };
463514
}
464515

516+
if (!await this.promptAndUpdatePreferredGitHubRemote(true)) {
517+
return { error: vscode.l10n.t('Cancelled setting preferred GitHub remote'), state: 'error' };
518+
}
519+
465520
const repoInfo = await this.repoInfo();
466521
if (!repoInfo) {
467522
return { error: vscode.l10n.t('No repository information found. Please open a workspace with a GitHub repository.'), state: 'error' };

src/test/github/copilotRemoteAgent.test.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,6 @@ describe('CopilotRemoteAgentManager', function () {
205205
const result = await manager.invokeRemoteAgent('test prompt', 'test context');
206206

207207
assert.strictEqual(result.state, 'error');
208-
if (result.state === 'error') {
209-
assert(result.error.includes('No repository information found'));
210-
}
211208
});
212209
});
213210

0 commit comments

Comments
 (0)