Parallelize some of the initial copilot token fetch (#835)

This commit is contained in:
Logan Ramos
2025-08-29 15:31:17 +00:00
committed by GitHub
parent 7f8f4a3cbb
commit 57e3d648ca
3 changed files with 15 additions and 14 deletions
@@ -103,10 +103,14 @@ export abstract class BaseCopilotTokenManager extends Disposable implements ICop
* @todo this should be not be public, but it is for now to allow testing.
*/
async authFromGitHubToken(
githubToken: string
githubToken: string,
ghUsername: string
): Promise<TokenInfoOrError & NotGitHubLoginFailed> {
this._telemetryService.sendGHTelemetryEvent('auth.new_login');
const response = await this.fetchCopilotToken(githubToken);
const [response, userInfo] = await Promise.all([
this.fetchCopilotToken(githubToken),
this.fetchCopilotUserInfo(githubToken)
]);
if (!response) {
this._logService.warn('Failed to get copilot token');
this._telemetryService.sendGHTelemetryErrorEvent('auth.request_failed');
@@ -149,12 +153,8 @@ export abstract class BaseCopilotTokenManager extends Disposable implements ICop
// adjust expires_at to the refresh time + a buffer to avoid expiring the token before the refresh can fire.
tokenInfo.expires_at = nowSeconds() + tokenInfo.refresh_in + 60; // extra buffer to allow refresh to happen successfully
// extend the token envelope
const userInfo = await this.fetchCopilotUserInfo(githubToken);
const authedUser = await this._baseOctokitservice.getCurrentAuthedUserWithToken(githubToken);
const login = authedUser?.login ?? 'unknown';
const login = ghUsername ?? 'unknown';
let isVscodeTeamMember = false;
// VS Code team members are guaranteed to be a part of an internal org so we can check that first to minimize API calls
if (containsInternalOrg(tokenInfo.organization_list ?? [])) {
@@ -262,6 +262,7 @@ export class CopilotTokenManagerFromGitHubToken extends BaseCopilotTokenManager
constructor(
private readonly githubToken: string,
private readonly githubUsername: string,
@ILogService logService: ILogService,
@ITelemetryService telemetryService: ITelemetryService,
@IDomainService domainService: IDomainService,
@@ -275,7 +276,7 @@ export class CopilotTokenManagerFromGitHubToken extends BaseCopilotTokenManager
async getCopilotToken(force?: boolean): Promise<CopilotToken> {
if (!this.copilotToken || this.copilotToken.expires_at < nowSeconds() - (60 * 5 /* 5min */) || force) {
const tokenResult = await this.authFromGitHubToken(this.githubToken);
const tokenResult = await this.authFromGitHubToken(this.githubToken, this.githubUsername);
if (tokenResult.kind === 'failure') {
throw Error(
`Failed to get copilot token: ${tokenResult.reason.toString()} ${tokenResult.message ?? ''}`
@@ -288,7 +289,7 @@ export class CopilotTokenManagerFromGitHubToken extends BaseCopilotTokenManager
async checkCopilotToken() {
if (!this.copilotToken || this.copilotToken.expires_at < nowSeconds()) {
const tokenResult = await this.authFromGitHubToken(this.githubToken);
const tokenResult = await this.authFromGitHubToken(this.githubToken, this.githubUsername);
if (tokenResult.kind === 'failure') {
return tokenResult;
}
@@ -73,7 +73,7 @@ describe('Copilot token unit tests', function () {
accessor = disposables.add(testingServiceCollection.createTestingAccessor());
const tokenManager = disposables.add(accessor.get(IInstantiationService).createInstance(RefreshFakeCopilotTokenManager, 1));
await tokenManager.authFromGitHubToken('fake-token');
await tokenManager.authFromGitHubToken('fake-token', 'fake-user');
expect(fetcher.requests.size).toBe(2);
});
@@ -103,7 +103,7 @@ describe('Copilot token unit tests', function () {
testingServiceCollection.define(IFetcherService, fetcher);
accessor = disposables.add(testingServiceCollection.createTestingAccessor());
const tokenManager = accessor.get(IInstantiationService).createInstance(CopilotTokenManagerFromGitHubToken, 'invalid');
const tokenManager = accessor.get(IInstantiationService).createInstance(CopilotTokenManagerFromGitHubToken, 'invalid', 'invalid-user');
const result = await tokenManager.checkCopilotToken();
expect(result).toEqual({
kind: 'failure',
@@ -121,7 +121,7 @@ describe('Copilot token unit tests', function () {
testingServiceCollection.define(IFetcherService, new ErrorFetcherService(expectedError));
accessor = disposables.add(testingServiceCollection.createTestingAccessor());
const tokenManager = accessor.get(IInstantiationService).createInstance(CopilotTokenManagerFromGitHubToken, 'invalid');
const tokenManager = accessor.get(IInstantiationService).createInstance(CopilotTokenManagerFromGitHubToken, 'invalid', 'invalid-user');
try {
await tokenManager.checkCopilotToken();
} catch (err: any) {
@@ -172,7 +172,7 @@ describe('Copilot token unit tests', function () {
accessor = disposables.add(testingServiceCollection.createTestingAccessor());
const tokenManager = disposables.add(accessor.get(IInstantiationService).createInstance(RefreshFakeCopilotTokenManager, 1));
await tokenManager.authFromGitHubToken('fake-token');
await tokenManager.authFromGitHubToken('fake-token', 'invalid-user');
expect(fetcher.requests.size).toBe(2);
});
@@ -66,7 +66,7 @@ export class VSCodeCopilotTokenManager extends BaseCopilotTokenManager {
}
// Log the steps by default, but only log actual token values when the log level is set to debug.
this._logService.info(`Logged in as ${session.account.label}`);
const tokenResult = await this.authFromGitHubToken(session.accessToken);
const tokenResult = await this.authFromGitHubToken(session.accessToken, session.account.label);
if (tokenResult.kind === 'success') {
this._logService.info(`Got Copilot token for ${session.account.label}`);
}