Skip to content

Commit 52126b6

Browse files
authored
Additional changes for custom org/enterprise agents (#2447)
* fix * fix test * fix * clean * experimental config
1 parent 82e805f commit 52126b6

File tree

4 files changed

+32
-27
lines changed

4 files changed

+32
-27
lines changed

package.json

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2503,11 +2503,6 @@
25032503
"default": true,
25042504
"description": "%github.copilot.config.customInstructionsInSystemMessage%"
25052505
},
2506-
"github.copilot.chat.customAgents.showOrganizationAndEnterpriseAgents": {
2507-
"type": "boolean",
2508-
"default": true,
2509-
"description": "%github.copilot.config.customAgents.showOrganizationAndEnterpriseAgents%"
2510-
},
25112506
"github.copilot.chat.agent.currentEditorContext.enabled": {
25122507
"type": "boolean",
25132508
"default": true,
@@ -3440,6 +3435,14 @@
34403435
"electron-fetch",
34413436
"node-fetch"
34423437
]
3438+
},
3439+
"github.copilot.chat.customAgents.showOrganizationAndEnterpriseAgents": {
3440+
"type": "boolean",
3441+
"default": false,
3442+
"description": "%github.copilot.config.customAgents.showOrganizationAndEnterpriseAgents%",
3443+
"tags": [
3444+
"experimental"
3445+
]
34433446
}
34443447
}
34453448
},

src/extension/agents/vscode-node/organizationAndEnterpriseAgentProvider.ts

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,19 @@ import { Disposable } from '../../../util/vs/base/common/lifecycle';
1414

1515
const AgentFileExtension = '.agent.md';
1616

17+
class UserNotSignedInError extends Error {
18+
constructor() {
19+
super('User is not signed in');
20+
}
21+
}
22+
1723
export class OrganizationAndEnterpriseAgentProvider extends Disposable implements vscode.CustomAgentsProvider {
1824

1925
private readonly _onDidChangeCustomAgents = this._register(new vscode.EventEmitter<void>());
2026
readonly onDidChangeCustomAgents = this._onDidChangeCustomAgents.event;
2127

2228
private isFetching = false;
23-
private memoryCache: vscode.CustomAgentResource[] | undefined = undefined;
29+
private memoryCache: vscode.CustomAgentResource[] | undefined;
2430

2531
constructor(
2632
@IOctoKitService private readonly octoKitService: IOctoKitService,
@@ -29,31 +35,29 @@ export class OrganizationAndEnterpriseAgentProvider extends Disposable implement
2935
@IFileSystemService private readonly fileSystem: IFileSystemService,
3036
) {
3137
super();
38+
39+
// Trigger async fetch to update cache. Note: this provider is re-created each time
40+
// the user signs in, so this will re-fetch on sign-in. See logic in conversationFeature.ts.
41+
this.fetchAndUpdateCache().catch(error => {
42+
this.logService.error(`[OrganizationAndEnterpriseAgentProvider] Error in background fetch: ${error}`);
43+
});
3244
}
3345

3446
private getCacheDir(): vscode.Uri {
3547
return vscode.Uri.joinPath(this.extensionContext.globalStorageUri, 'githubAgentsCache');
3648
}
3749

3850
async provideCustomAgents(
39-
options: vscode.CustomAgentQueryOptions,
51+
_options: vscode.CustomAgentQueryOptions,
4052
_token: vscode.CancellationToken
4153
): Promise<vscode.CustomAgentResource[]> {
4254
try {
43-
// If we have successfully fetched and cached in memory, return from memory
4455
if (this.memoryCache !== undefined) {
4556
return this.memoryCache;
4657
}
4758

48-
// Read from file cache first
49-
const fileCachedAgents = await this.readFromCache();
50-
51-
// Trigger async fetch to update cache
52-
this.fetchAndUpdateCache(options).catch(error => {
53-
this.logService.error(`[OrganizationAndEnterpriseAgentProvider] Error in background fetch: ${error}`);
54-
});
55-
56-
return fileCachedAgents;
59+
// Return results from file cache
60+
return await this.readFromCache();
5761
} catch (error) {
5862
this.logService.error(`[OrganizationAndEnterpriseAgentProvider] Error in provideCustomAgents: ${error}`);
5963
return [];
@@ -113,14 +117,12 @@ export class OrganizationAndEnterpriseAgentProvider extends Disposable implement
113117
private async runWithAuthCheck<T>(operation: () => Promise<T>): Promise<T> {
114118
const user = await this.octoKitService.getCurrentAuthedUser();
115119
if (!user) {
116-
throw new Error('User is not signed in');
120+
throw new UserNotSignedInError();
117121
}
118122
return operation();
119123
}
120124

121-
private async fetchAndUpdateCache(
122-
options: vscode.CustomAgentQueryOptions
123-
): Promise<void> {
125+
private async fetchAndUpdateCache(): Promise<void> {
124126
// Prevent concurrent fetches
125127
if (this.isFetching) {
126128
this.logService.trace('[OrganizationAndEnterpriseAgentProvider] Fetch already in progress, skipping');
@@ -147,9 +149,9 @@ export class OrganizationAndEnterpriseAgentProvider extends Disposable implement
147149
this.logService.trace(`[OrganizationAndEnterpriseAgentProvider] Found ${organizations.length} organizations: ${organizations.join(', ')}`);
148150

149151
// Convert VS Code API options to internal options
150-
const internalOptions = options ? {
152+
const internalOptions = {
151153
includeSources: ['org', 'enterprise'] // don't include 'repo'
152-
} satisfies CustomAgentListOptions : undefined;
154+
} satisfies CustomAgentListOptions;
153155

154156
// Fetch agents from all organizations
155157
const agentsByOrg = new Map<string, Map<string, CustomAgentListItem>>();
@@ -175,7 +177,7 @@ export class OrganizationAndEnterpriseAgentProvider extends Disposable implement
175177
}
176178
this.logService.trace(`[OrganizationAndEnterpriseAgentProvider] Fetched ${agents.length} agents from ${org} using repo ${repoName}`);
177179
} catch (error) {
178-
if (error instanceof Error && error.message === 'User is not signed in') {
180+
if (error instanceof UserNotSignedInError) {
179181
this.logService.trace('[OrganizationAndEnterpriseAgentProvider] User signed out during fetch, aborting');
180182
return;
181183
}
@@ -254,7 +256,7 @@ export class OrganizationAndEnterpriseAgentProvider extends Disposable implement
254256
totalAgents++;
255257
}
256258
} catch (error) {
257-
if (error instanceof Error && error.message === 'User is not signed in') {
259+
if (error instanceof UserNotSignedInError) {
258260
this.logService.trace('[OrganizationAndEnterpriseAgentProvider] User signed out during fetch, aborting');
259261
return;
260262
}

src/extension/agents/vscode-node/test/organizationAndEnterpriseAgentProvider.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ suite('OrganizationAndEnterpriseAgentProvider', () => {
115115
mockOctoKitService,
116116
accessor.get(ILogService),
117117
mockExtensionContext as any,
118-
mockFileSystem
118+
mockFileSystem,
119119
);
120120
disposables.add(provider);
121121
return provider;

src/platform/configuration/common/configurationService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,7 @@ export namespace ConfigKey {
868868
export const EnableAlternateGptPrompt = defineSetting<boolean>('chat.alternateGptPrompt.enabled', ConfigType.ExperimentBased, false);
869869

870870
/** Enable custom agents from GitHub Enterprise/Organizations */
871-
export const ShowOrganizationAndEnterpriseAgents = defineSetting<boolean>('chat.customAgents.showOrganizationAndEnterpriseAgents', ConfigType.Simple, true);
871+
export const ShowOrganizationAndEnterpriseAgents = defineSetting<boolean>('chat.customAgents.showOrganizationAndEnterpriseAgents', ConfigType.Simple, false);
872872

873873
export const CompletionsFetcher = defineSetting<FetcherId | undefined>('chat.completionsFetcher', ConfigType.ExperimentBased, undefined);
874874
export const NextEditSuggestionsFetcher = defineSetting<FetcherId | undefined>('chat.nesFetcher', ConfigType.ExperimentBased, undefined);

0 commit comments

Comments
 (0)