Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/extension/extension/vscode/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,25 @@ export async function baseActivate(configuration: IExtensionActivationConfigurat
await contributions.waitForActivationBlockers();
});

// DEBUG: Test call to organization custom instructions service
instantiationService.invokeFunction(async accessor => {
const { IOrgCustomInstructionsService } = await import('../../../platform/customInstructions/common/orgCustomInstructionsService');
const orgInstructionsService = accessor.get(IOrgCustomInstructionsService);
console.log('[DEBUG] Testing OrgCustomInstructionsService...');
try {
const instructions = await orgInstructionsService.getOrgCustomInstructions();
if (instructions) {
console.log('[DEBUG] Successfully fetched org custom instructions:', instructions.substring(0, 200) + (instructions.length > 200 ? '...' : ''));
} else {
console.log('[DEBUG] No org custom instructions available');
}
} catch (error) {
console.error('[DEBUG] Error fetching org custom instructions:', error);
}
}).catch(error => {
console.error('[DEBUG] Failed to test OrgCustomInstructionsService:', error);
});

if (ExtensionMode.Test === context.extensionMode && !isScenarioAutomation) {
return instantiationService; // The returned accessor is used in tests
}
Expand Down
2 changes: 2 additions & 0 deletions src/extension/extension/vscode/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { RunCommandExecutionServiceImpl } from '../../../platform/commands/vscod
import { IConfigurationService } from '../../../platform/configuration/common/configurationService';
import { ConfigurationServiceImpl } from '../../../platform/configuration/vscode/configurationServiceImpl';
import { CustomInstructionsService, ICustomInstructionsService } from '../../../platform/customInstructions/common/customInstructionsService';
import { IOrgCustomInstructionsService, OrgCustomInstructionsService } from '../../../platform/customInstructions/common/orgCustomInstructionsService';
import { IDebugOutputService } from '../../../platform/debug/common/debugOutputService';
import { DebugOutputServiceImpl } from '../../../platform/debug/vscode/debugOutputServiceImpl';
import { IDialogService } from '../../../platform/dialog/common/dialogService';
Expand Down Expand Up @@ -158,6 +159,7 @@ export function registerServices(builder: IInstantiationServiceBuilder, extensio
builder.define(IEditLogService, new SyncDescriptor(EditLogService));
builder.define(IMultiFileEditInternalTelemetryService, new SyncDescriptor(MultiFileEditInternalTelemetryService));
builder.define(ICustomInstructionsService, new SyncDescriptor(CustomInstructionsService));
builder.define(IOrgCustomInstructionsService, new SyncDescriptor(OrgCustomInstructionsService));
builder.define(ILaunchConfigService, new SyncDescriptor(LaunchConfigService));
builder.define(ISurveyService, new SyncDescriptor(SurveyService));
builder.define(IEditSurvivalTrackerService, new SyncDescriptor(EditSurvivalTrackerService));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { RequestType } from '@vscode/copilot-api';
import { createServiceIdentifier } from '../../../util/common/services';
import { IAuthenticationService } from '../../authentication/common/authentication';
import { ICAPIClientService } from '../../endpoint/common/capiClient';
import { ILogService } from '../../log/common/logService';

export const IOrgCustomInstructionsService = createServiceIdentifier<IOrgCustomInstructionsService>('IOrgCustomInstructionsService');

export interface IOrgCustomInstructionsService {
readonly _serviceBrand: undefined;

/**
* Fetches custom instructions for the current active GitHub organization
* @returns The custom instructions as a string, or undefined if not available
*/
getOrgCustomInstructions(): Promise<string | undefined>;
}

export class OrgCustomInstructionsService implements IOrgCustomInstructionsService {
readonly _serviceBrand: undefined;

constructor(
@ICAPIClientService private readonly _capiClientService: ICAPIClientService,
@IAuthenticationService private readonly _authenticationService: IAuthenticationService,
@ILogService private readonly _logService: ILogService,
) { }

async getOrgCustomInstructions(): Promise<string | undefined> {
try {
// Get the copilot token to access organization info
const copilotToken = await this._authenticationService.getCopilotToken();
if (!copilotToken) {
this._logService.debug('[OrgCustomInstructions] No copilot token found');
return undefined;
}

// Check for numeric organization ID from enterprise list first (preferred)
let organizationId: number | undefined;
if (copilotToken.enterpriseList && copilotToken.enterpriseList.length > 0) {
organizationId = copilotToken.enterpriseList[0];
this._logService.debug(`[OrgCustomInstructions] Using enterprise ID: ${organizationId}`);
} else if (copilotToken.organizationList && copilotToken.organizationList.length > 0) {
// Try to parse the organization ID from the organization list (hash-based IDs)
// Note: The organizationList contains hash strings, not numeric IDs
// For the example request showing organization_id: 12345, this would need to come from
// a different source or API that maps org names to numeric IDs
const orgHash = copilotToken.organizationList[0];
this._logService.debug(`[OrgCustomInstructions] Organization hash found: ${orgHash}`);
this._logService.warn('[OrgCustomInstructions] Cannot convert organization hash to numeric ID. Numeric organization ID required.');
return undefined;
} else {
this._logService.debug('[OrgCustomInstructions] No organization or enterprise ID found in copilot token');
return undefined;
}

this._logService.debug(`[OrgCustomInstructions] Fetching instructions for organization ID: ${organizationId}`);

const response = await this._capiClientService.makeRequest<Response>(
{
method: 'POST',
json: { organization_id: organizationId },
headers: { 'Content-Type': 'application/json' }
},
{ type: RequestType.OrgCustomInstructions, organizationId }

Check failure on line 69 in src/platform/customInstructions/common/orgCustomInstructionsService.ts

View workflow job for this annotation

GitHub Actions / Test (Windows)

Object literal may only specify known properties, and 'organizationId' does not exist in type 'RequestMetadata'.

Check failure on line 69 in src/platform/customInstructions/common/orgCustomInstructionsService.ts

View workflow job for this annotation

GitHub Actions / Test (Windows)

Property 'OrgCustomInstructions' does not exist on type 'typeof RequestType'.

Check failure on line 69 in src/platform/customInstructions/common/orgCustomInstructionsService.ts

View workflow job for this annotation

GitHub Actions / Test (Linux)

Object literal may only specify known properties, and 'organizationId' does not exist in type 'RequestMetadata'.

Check failure on line 69 in src/platform/customInstructions/common/orgCustomInstructionsService.ts

View workflow job for this annotation

GitHub Actions / Test (Linux)

Property 'OrgCustomInstructions' does not exist on type 'typeof RequestType'.
);

if (!response.ok) {
this._logService.warn(`[OrgCustomInstructions] Failed to fetch instructions: ${response.status} ${response.statusText}`);
return undefined;
}

const data = await response.json();

// Assuming the API returns an object with an 'instructions' field
if (typeof data === 'object' && data !== null && 'instructions' in data && typeof data.instructions === 'string') {
this._logService.debug(`[OrgCustomInstructions] Successfully fetched instructions (${data.instructions.length} chars)`);
return data.instructions;
}

this._logService.warn('[OrgCustomInstructions] Unexpected response format from API');
return undefined;

} catch (error) {
this._logService.error(`[OrgCustomInstructions] Error fetching organization custom instructions: ${error}`);
return undefined;
}
}
}
Loading