Skip to content

Commit f0e2e51

Browse files
authored
handle jobs api errors (#7114)
1 parent be7631d commit f0e2e51

2 files changed

Lines changed: 47 additions & 18 deletions

File tree

src/github/copilotApi.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,36 @@ export class CopilotApi {
5656
body: JSON.stringify(payload)
5757
});
5858
if (!response.ok) {
59-
const text = await response.text();
60-
throw new Error(`Coding agent API error: ${response.status} ${text}`);
59+
throw new Error(this.formatRemoteAgentJobError(response.status));
6160
}
6261
const data = await response.json();
6362
this.validateRemoteAgentJobResponse(data);
6463
return data;
6564
}
6665

66+
67+
// https://github.com/github/sweagentd/blob/371ea6db280b9aecf790ccc20660e39a7ecb8d1c/internal/api/jobapi/handler.go#L110-L120
68+
private formatRemoteAgentJobError(status: number) {
69+
switch (status) {
70+
case 400:
71+
return 'Bad request';
72+
case 401:
73+
return 'Unauthorized';
74+
case 402:
75+
return 'Premium request quota exceeded';
76+
case 403:
77+
return 'GitHub Coding Agent is not enabled for this repository';
78+
case 404:
79+
return 'Repository not found';
80+
case 409:
81+
return 'A Coding Agent pull request already exists';
82+
case 500:
83+
return 'Server error';
84+
default:
85+
return `Error: ${status}`;
86+
}
87+
}
88+
6789
private validateRemoteAgentJobResponse(data: any): asserts data is RemoteAgentJobResponse {
6890
if (!data || typeof data !== 'object') {
6991
throw new Error('Invalid response from coding agent');

src/github/copilotRemoteAgent.ts

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,6 @@ export class CopilotRemoteAgentManager extends Disposable {
276276
}
277277

278278
async invokeRemoteAgent(prompt: string, problemContext: string, autoPushAndCommit = true): Promise<RemoteAgentResult> {
279-
// TODO: Check that the user has a valid copilot subscription
280279
const capiClient = await this.copilotApi;
281280
if (!capiClient) {
282281
return { error: vscode.l10n.t('Failed to initialize Copilot API'), state: 'error' };
@@ -303,22 +302,25 @@ export class CopilotRemoteAgentManager extends Disposable {
303302
await repository.createBranch(asyncBranch, true);
304303
await repository.add([]);
305304
if (repository.state.indexChanges.length > 0) {
306-
// TODO: there is an issue here if the user has GPG signing enabled.
307-
// https://github.com/microsoft/vscode/pull/252263
308-
await repository.commit('Checkpoint for Copilot Agent async session', { signCommit: false });
305+
try {
306+
await repository.commit('Checkpoint for Copilot Agent async session', { signCommit: false });
307+
} catch (e) {
308+
// https://github.com/microsoft/vscode/pull/252263
309+
return { error: vscode.l10n.t('Could not \'git commit\' pending changes. If GPG signing or git hooks are enabled, please first commit or stash your changes and try again. ({0})', e.message), state: 'error' };
310+
}
309311
}
310312
await repository.push(remote, asyncBranch, true);
311313
ref = asyncBranch;
312314
} catch (e) {
313-
return { error: vscode.l10n.t(`Could not auto-commit pending changes. Please disable GPG signing, or manually commit/stash your changes before starting the remote agent. Error: ${e.message}`), state: 'error' };
315+
return { error: vscode.l10n.t('Could not auto-push pending changes. Manually commit or stash your changes and try again. ({0})', e.message), state: 'error' };
314316
} finally {
315317
// Swap back to the original branch without your pending changes
316318
// TODO: Better if we show a confirmation dialog in chat
317319
if (repository.state.HEAD?.name !== baseRef) {
318320
// show notification asking the user if they want to switch back to the original branch
319321
const SWAP_BACK_TO_ORIGINAL_BRANCH = vscode.l10n.t(`Swap back to '{0}'`, baseRef);
320322
vscode.window.showInformationMessage(
321-
vscode.l10n.t(`Your pending changes have been pushed to remote branch '{0}.`, ref),
323+
vscode.l10n.t(`Pending changes pushed to remote branch '{0}'.`, ref),
322324
SWAP_BACK_TO_ORIGINAL_BRANCH,
323325
).then(async (selection) => {
324326
if (selection === SWAP_BACK_TO_ORIGINAL_BRANCH) {
@@ -345,16 +347,21 @@ export class CopilotRemoteAgentManager extends Disposable {
345347
...(hasChanges && autoPushAndCommit && { head_ref: ref })
346348
}
347349
};
348-
const { pull_request } = await capiClient.postRemoteAgentJob(owner, repo, payload);
349-
const webviewUri = await toOpenPullRequestWebviewUri({ owner, repo, pullRequestNumber: pull_request.number });
350-
const prLlmString = `The remote agent has begun work. The user can track progress by visiting ${pull_request.html_url} or from the PR extension. Format this VS Code webview link so the user can click it to also track progress: ${webviewUri.toString()}`;
351-
return {
352-
state: 'success',
353-
number: pull_request.number,
354-
link: pull_request.html_url,
355-
webviewUri,
356-
llmDetails: hasChanges ? `The pending changes have been pushed to branch '${ref}'. ${prLlmString}` : prLlmString
357-
};
350+
351+
try {
352+
const { pull_request } = await capiClient.postRemoteAgentJob(owner, repo, payload);
353+
const webviewUri = await toOpenPullRequestWebviewUri({ owner, repo, pullRequestNumber: pull_request.number });
354+
const prLlmString = `The remote agent has begun work. The user can track progress by visiting ${pull_request.html_url} or from the PR extension. Format this VS Code webview link so the user can click it to also track progress: ${webviewUri.toString()}`;
355+
return {
356+
state: 'success',
357+
number: pull_request.number,
358+
link: pull_request.html_url,
359+
webviewUri,
360+
llmDetails: hasChanges ? `The pending changes have been pushed to branch '${ref}'. ${prLlmString}` : prLlmString
361+
};
362+
} catch (error) {
363+
return { error: error.message, state: 'error' };
364+
}
358365
}
359366

360367
async getSessionLogsFromAction(remote: Remote, pullRequestId: number) {

0 commit comments

Comments
 (0)