diff --git a/extensions/copilot/src/extension/prompt/node/chatMLFetcher.ts b/extensions/copilot/src/extension/prompt/node/chatMLFetcher.ts index a3dc969c135..ea42bfbfdc3 100644 --- a/extensions/copilot/src/extension/prompt/node/chatMLFetcher.ts +++ b/extensions/copilot/src/extension/prompt/node/chatMLFetcher.ts @@ -32,7 +32,6 @@ import { IExperimentationService } from '../../../platform/telemetry/common/null import { ITelemetryService, TelemetryProperties } from '../../../platform/telemetry/common/telemetry'; import { TelemetryData } from '../../../platform/telemetry/common/telemetryData'; import { calculateLineRepetitionStats, isRepetitive } from '../../../util/common/anomalyDetection'; -import { createRequestHMAC } from '../../../util/common/crypto'; import * as errorsUtil from '../../../util/common/errors'; import { AsyncIterableObject } from '../../../util/vs/base/common/async'; import { isCancellationError } from '../../../util/vs/base/common/errors'; @@ -40,6 +39,7 @@ import { Emitter } from '../../../util/vs/base/common/event'; import { Disposable } from '../../../util/vs/base/common/lifecycle'; import { escapeRegExpCharacters } from '../../../util/vs/base/common/strings'; import { generateUuid } from '../../../util/vs/base/common/uuid'; +import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation'; import { isBYOKModel } from '../../byok/node/openAIEndpoint'; import { EXTENSION_ID } from '../../common/constants'; import { IPowerService } from '../../power/common/powerService'; @@ -113,6 +113,7 @@ export class ChatMLFetcherImpl extends AbstractChatMLFetcher { @IConfigurationService private readonly _configurationService: IConfigurationService, @IExperimentationService private readonly _experimentationService: IExperimentationService, @IPowerService private readonly _powerService: IPowerService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { super(options); } @@ -868,22 +869,18 @@ export class ChatMLFetcherImpl extends AbstractChatMLFetcher { const intent = locationToIntent(location); // Wrap the Promise with success/error callbacks so we can log/measure it - return postRequest( - this._fetcherService, - this._telemetryService, - this._capiClientService, - chatEndpoint, + return this._instantiationService.invokeFunction(postRequest, { + endpointOrUrl: chatEndpoint, secretKey, - await createRequestHMAC(process.env.HMAC_SECRET), intent, - ourRequestId, - request, + requestId: ourRequestId, + body: request, additionalHeaders, - cancellationToken, + cancelToken: cancellationToken, useFetcher, canRetryOnce, location, - ).then(response => { + }).then(response => { const apim = response.headers.get('apim-request-id'); if (apim) { this._logService.debug(`APIM request id: ${apim}`); diff --git a/extensions/copilot/src/extension/prompt/node/test/chatMLFetcherResponseApiTelemetry.spec.ts b/extensions/copilot/src/extension/prompt/node/test/chatMLFetcherResponseApiTelemetry.spec.ts index 853d8e4294a..6d6be3fea07 100644 --- a/extensions/copilot/src/extension/prompt/node/test/chatMLFetcherResponseApiTelemetry.spec.ts +++ b/extensions/copilot/src/extension/prompt/node/test/chatMLFetcherResponseApiTelemetry.spec.ts @@ -27,9 +27,11 @@ import { ITelemetryService } from '../../../../platform/telemetry/common/telemet import { TelemetryData } from '../../../../platform/telemetry/common/telemetryData'; import { SpyingTelemetryService } from '../../../../platform/telemetry/node/spyingTelemetryService'; import { TestLogService } from '../../../../platform/testing/common/testLogService'; +import { InstantiationServiceBuilder } from '../../../../util/common/services'; import { CancellationToken, CancellationTokenSource } from '../../../../util/vs/base/common/cancellation'; import { Event } from '../../../../util/vs/base/common/event'; import { DisposableStore } from '../../../../util/vs/base/common/lifecycle'; +import { IInstantiationService } from '../../../../util/vs/platform/instantiation/common/instantiation'; import { IPowerService, NullPowerService } from '../../../power/common/powerService'; import { ChatMLFetcherImpl } from '../chatMLFetcher'; @@ -64,6 +66,11 @@ describe('ChatMLFetcherImpl Response API telemetry', () => { configurationService, experimentationService, createMockPowerService(), + new InstantiationServiceBuilder([ + [IFetcherService, mockFetcherService as unknown as IFetcherService], + [ITelemetryService, spyingTelemetryService], + [ICAPIClientService, new TestCAPIClientService() as unknown as ICAPIClientService], + ]).seal() as unknown as IInstantiationService, ); }); diff --git a/extensions/copilot/src/extension/prompt/node/test/chatMLFetcherRetry.spec.ts b/extensions/copilot/src/extension/prompt/node/test/chatMLFetcherRetry.spec.ts index e4a144c2f8d..40bbf126df8 100644 --- a/extensions/copilot/src/extension/prompt/node/test/chatMLFetcherRetry.spec.ts +++ b/extensions/copilot/src/extension/prompt/node/test/chatMLFetcherRetry.spec.ts @@ -27,9 +27,11 @@ import { NullTelemetryService } from '../../../../platform/telemetry/common/null import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry'; import { TelemetryData } from '../../../../platform/telemetry/common/telemetryData'; import { TestLogService } from '../../../../platform/testing/common/testLogService'; +import { InstantiationServiceBuilder } from '../../../../util/common/services'; import { CancellationToken, CancellationTokenSource } from '../../../../util/vs/base/common/cancellation'; import { Event } from '../../../../util/vs/base/common/event'; import { DisposableStore } from '../../../../util/vs/base/common/lifecycle'; +import { IInstantiationService } from '../../../../util/vs/platform/instantiation/common/instantiation'; import { IPowerService, NullPowerService } from '../../../power/common/powerService'; import { ChatMLFetcherImpl } from '../chatMLFetcher'; @@ -69,6 +71,11 @@ describe('ChatMLFetcherImpl retry logic', () => { configurationService, experimentationService, createMockPowerService(), + new InstantiationServiceBuilder([ + [IFetcherService, mockFetcherService as unknown as IFetcherService], + [ITelemetryService, telemetryService], + [ICAPIClientService, new TestCAPIClientService() as unknown as ICAPIClientService], + ]).seal() as unknown as IInstantiationService, ); // Skip delays in tests for faster execution diff --git a/extensions/copilot/src/extension/prompt/vscode-node/endpointProviderImpl.ts b/extensions/copilot/src/extension/prompt/vscode-node/endpointProviderImpl.ts index 3e9d28897d1..708ef42a3e0 100644 --- a/extensions/copilot/src/extension/prompt/vscode-node/endpointProviderImpl.ts +++ b/extensions/copilot/src/extension/prompt/vscode-node/endpointProviderImpl.ts @@ -6,7 +6,6 @@ import { LanguageModelChat, type ChatRequest } from 'vscode'; import { IAuthenticationService } from '../../../platform/authentication/common/authentication'; import { ConfigKey, IConfigurationService } from '../../../platform/configuration/common/configurationService'; -import { ICAPIClientService } from '../../../platform/endpoint/common/capiClient'; import { ChatEndpointFamily, EmbeddingsEndpointFamily, IChatModelInformation, ICompletionModelInformation, IEmbeddingModelInformation, IEndpointProvider } from '../../../platform/endpoint/common/endpointProvider'; import { AutoChatEndpoint } from '../../../platform/endpoint/node/autoChatEndpoint'; import { IAutomodeService } from '../../../platform/endpoint/node/automodeService'; @@ -14,13 +13,8 @@ import { CopilotChatEndpoint } from '../../../platform/endpoint/node/copilotChat import { EmbeddingEndpoint } from '../../../platform/endpoint/node/embeddingsEndpoint'; import { IModelMetadataFetcher, ModelMetadataFetcher } from '../../../platform/endpoint/node/modelMetadataFetcher'; import { ExtensionContributedChatEndpoint } from '../../../platform/endpoint/vscode-node/extChatEndpoint'; -import { IEnvService } from '../../../platform/env/common/envService'; import { ILogService } from '../../../platform/log/common/logService'; -import { IFetcherService } from '../../../platform/networking/common/fetcherService'; import { IChatEndpoint, IEmbeddingsEndpoint } from '../../../platform/networking/common/networking'; -import { IRequestLogger } from '../../../platform/requestLogger/node/requestLogger'; -import { IExperimentationService } from '../../../platform/telemetry/common/nullExperimentationService'; -import { ITelemetryService } from '../../../platform/telemetry/common/telemetry'; import { TokenizerType } from '../../../util/common/tokenizer'; import { Emitter, Event } from '../../../util/vs/base/common/event'; import { Disposable } from '../../../util/vs/base/common/lifecycle'; @@ -39,31 +33,16 @@ export class ProductionEndpointProvider extends Disposable implements IEndpointP private readonly _modelFetcher: IModelMetadataFetcher; constructor( - @ICAPIClientService capiClientService: ICAPIClientService, - @IFetcherService fetcher: IFetcherService, @IAutomodeService private readonly _autoModeService: IAutomodeService, - @IExperimentationService private readonly _expService: IExperimentationService, - @ITelemetryService private readonly _telemetryService: ITelemetryService, @ILogService protected readonly _logService: ILogService, @IConfigurationService protected readonly _configService: IConfigurationService, @IInstantiationService protected readonly _instantiationService: IInstantiationService, - @IEnvService _envService: IEnvService, @IAuthenticationService protected readonly _authService: IAuthenticationService, - @IRequestLogger _requestLogger: IRequestLogger ) { super(); - this._modelFetcher = new ModelMetadataFetcher( + this._modelFetcher = this._instantiationService.createInstance(ModelMetadataFetcher, false, - fetcher, - _requestLogger, - capiClientService, - this._configService, - this._expService, - _envService, - _authService, - this._telemetryService, - _logService, ); // When new models come in from CAPI we want to clear our local caches and let the endpoints be recreated since there may be new info diff --git a/extensions/copilot/src/platform/chunking/common/chunkingEndpointClientImpl.ts b/extensions/copilot/src/platform/chunking/common/chunkingEndpointClientImpl.ts index 8797e8c17b9..f1a4429b285 100644 --- a/extensions/copilot/src/platform/chunking/common/chunkingEndpointClientImpl.ts +++ b/extensions/copilot/src/platform/chunking/common/chunkingEndpointClientImpl.ts @@ -4,24 +4,20 @@ *--------------------------------------------------------------------------------------------*/ import { RequestType } from '@vscode/copilot-api'; -import { createRequestHMAC } from '../../../util/common/crypto'; import { CallTracker } from '../../../util/common/telemetryCorrelationId'; import { coalesce } from '../../../util/vs/base/common/arrays'; import { DeferredPromise, raceCancellationError, timeout } from '../../../util/vs/base/common/async'; import { CancellationToken } from '../../../util/vs/base/common/cancellation'; -import { Lazy } from '../../../util/vs/base/common/lazy'; import { Disposable } from '../../../util/vs/base/common/lifecycle'; import { LinkedList } from '../../../util/vs/base/common/linkedList'; -import { env } from '../../../util/vs/base/common/process'; import { isFalsyOrWhitespace } from '../../../util/vs/base/common/strings'; import { Range } from '../../../util/vs/editor/common/core/range'; import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation'; import { Embedding, EmbeddingType, EmbeddingVector } from '../../embeddings/common/embeddingsComputer'; -import { ICAPIClientService } from '../../endpoint/common/capiClient'; import { IEnvService } from '../../env/common/envService'; import { logExecTime } from '../../log/common/logExecTime'; import { ILogService } from '../../log/common/logService'; -import { IFetcherService, Response } from '../../networking/common/fetcherService'; +import { Response } from '../../networking/common/fetcherService'; import { postRequest } from '../../networking/common/networking'; import { IExperimentationService } from '../../telemetry/common/nullExperimentationService'; import { ITelemetryService } from '../../telemetry/common/telemetry'; @@ -295,20 +291,16 @@ export class ChunkingEndpointClientImpl extends Disposable implements IChunkingE */ private readonly _requestLimiter: RequestRateLimiter; - private readonly _requestHmac = new Lazy(() => createRequestHMAC(env.HMAC_SECRET)); - constructor( - @IInstantiationService instantiationService: IInstantiationService, - @ICAPIClientService private readonly _capiClientService: ICAPIClientService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, @IEnvService private readonly _envService: IEnvService, - @IFetcherService private readonly _fetcherService: IFetcherService, @ILogService private readonly _logService: ILogService, @ITelemetryService private readonly _telemetryService: ITelemetryService, @IWorkspaceService private readonly _workspaceService: IWorkspaceService, ) { super(); - this._requestLimiter = this._register(instantiationService.createInstance(RequestRateLimiter)); + this._requestLimiter = this._register(this._instantiationService.createInstance(RequestRateLimiter)); } public computeChunks(authToken: string, embeddingType: EmbeddingType, content: ChunkableContent, batchInfo: ComputeBatchInfo, qos: EmbeddingsComputeQos, cache: ReadonlyMap | undefined, telemetryInfo: CallTracker, token: CancellationToken): Promise { @@ -339,19 +331,13 @@ export class ChunkingEndpointClientImpl extends Disposable implements IChunkingE } try { - const hmac = await raceCancellationError(this._requestHmac.value, token); - const makeRequest = async (attempt: number) => { - return logExecTime(this._logService, `ChunksEndpointEmbeddingComputer.fetchChunksRequest(${content.uri}, attempt=${attempt})`, () => postRequest( - this._fetcherService, - this._telemetryService, - this._capiClientService, - { type: RequestType.Chunks }, - authToken, - hmac, - 'copilot-panel', - '', - { + return logExecTime(this._logService, `ChunksEndpointEmbeddingComputer.fetchChunksRequest(${content.uri}, attempt=${attempt})`, () => this._instantiationService.invokeFunction(postRequest, { + endpointOrUrl: { type: RequestType.Chunks }, + secretKey: authToken, + intent: 'copilot-panel', + requestId: '', + body: { embed: options.computeEmbeddings, // Only to online set during re-ranking step qos: options.qos, @@ -369,8 +355,9 @@ export class ChunkingEndpointClientImpl extends Disposable implements IChunkingE language_id: number | undefined; embedding_model: string; } as any, - getGithubMetadataHeaders(telemetryInfo, this._envService), - token)); + additionalHeaders: getGithubMetadataHeaders(telemetryInfo, this._envService), + cancelToken: token, + })); }; batchInfo.recomputedFileCount++; diff --git a/extensions/copilot/src/platform/embeddings/common/remoteEmbeddingsComputer.ts b/extensions/copilot/src/platform/embeddings/common/remoteEmbeddingsComputer.ts index 65306d13f6d..3feb8dab50e 100644 --- a/extensions/copilot/src/platform/embeddings/common/remoteEmbeddingsComputer.ts +++ b/extensions/copilot/src/platform/embeddings/common/remoteEmbeddingsComputer.ts @@ -5,19 +5,16 @@ import { RequestType } from '@vscode/copilot-api'; import type { CancellationToken } from 'vscode'; -import { createRequestHMAC } from '../../../util/common/crypto'; import { CallTracker, TelemetryCorrelationId } from '../../../util/common/telemetryCorrelationId'; import { Limiter } from '../../../util/vs/base/common/async'; -import { env } from '../../../util/vs/base/common/process'; import { generateUuid } from '../../../util/vs/base/common/uuid'; +import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation'; import { IAuthenticationService } from '../../authentication/common/authentication'; import { getGithubMetadataHeaders } from '../../chunking/common/chunkingEndpointClientImpl'; -import { ICAPIClientService } from '../../endpoint/common/capiClient'; import { IEndpointProvider } from '../../endpoint/common/endpointProvider'; import { IEnvService } from '../../env/common/envService'; import { logExecTime } from '../../log/common/logExecTime'; import { ILogService } from '../../log/common/logService'; -import { IFetcherService } from '../../networking/common/fetcherService'; import { IEmbeddingsEndpoint, postRequest } from '../../networking/common/networking'; import { ITelemetryService } from '../../telemetry/common/telemetry'; import { ComputeEmbeddingsOptions, Embedding, EmbeddingType, EmbeddingTypeInfo, EmbeddingVector, Embeddings, IEmbeddingsComputer, getWellKnownEmbeddingTypeInfo } from './embeddingsComputer'; @@ -39,12 +36,11 @@ export class RemoteEmbeddingsComputer implements IEmbeddingsComputer { constructor( @IAuthenticationService private readonly _authService: IAuthenticationService, - @ICAPIClientService private readonly _capiClientService: ICAPIClientService, @IEnvService private readonly _envService: IEnvService, - @IFetcherService private readonly _fetcherService: IFetcherService, @ILogService private readonly _logService: ILogService, @ITelemetryService private readonly _telemetryService: ITelemetryService, @IEndpointProvider private readonly _endpointProvider: IEndpointProvider, + @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { } public async computeEmbeddings( @@ -84,19 +80,15 @@ export class RemoteEmbeddingsComputer implements IEmbeddingsComputer { input_type: options?.inputType ?? 'document', embedding_model: embeddingType.id, }; - const response = await postRequest( - this._fetcherService, - this._telemetryService, - this._capiClientService, - { type: RequestType.DotcomEmbeddings }, - token, - await createRequestHMAC(env.HMAC_SECRET), - 'copilot-panel', - generateUuid(), - body as any, - getGithubMetadataHeaders(telemetryInfo?.callTracker ?? new CallTracker(), this._envService), - cancellationToken - ); + const response = await this._instantiationService.invokeFunction(postRequest, { + endpointOrUrl: { type: RequestType.DotcomEmbeddings }, + secretKey: token, + intent: 'copilot-panel', + requestId: generateUuid(), + body: body as any, + additionalHeaders: getGithubMetadataHeaders(telemetryInfo?.callTracker ?? new CallTracker(), this._envService), + cancelToken: cancellationToken, + }); if (!response.ok) { /* __GDPR__ "remoteEmbeddingsComputer.computeEmbeddings.error" : { @@ -268,19 +260,14 @@ export class RemoteEmbeddingsComputer implements IEmbeddingsComputer { const body = { input: inputs, model: type.model, dimensions: type.dimensions }; endpoint.interceptBody?.(body); - const response = await postRequest( - this._fetcherService, - this._telemetryService, - this._capiClientService, - endpoint, - token.token, - await createRequestHMAC(env.HMAC_SECRET), - 'copilot-panel', + const response = await this._instantiationService.invokeFunction(postRequest, { + endpointOrUrl: endpoint, + secretKey: token.token, + intent: 'copilot-panel', requestId, body, - undefined, - cancellationToken - ); + cancelToken: cancellationToken, + }); const jsonResponse = response.status === 200 ? await response.json() : await response.text(); type EmbeddingResponse = { diff --git a/extensions/copilot/src/platform/endpoint/node/modelMetadataFetcher.ts b/extensions/copilot/src/platform/endpoint/node/modelMetadataFetcher.ts index 177b8420324..318b193a506 100644 --- a/extensions/copilot/src/platform/endpoint/node/modelMetadataFetcher.ts +++ b/extensions/copilot/src/platform/endpoint/node/modelMetadataFetcher.ts @@ -5,22 +5,19 @@ import { RequestType } from '@vscode/copilot-api'; import type { LanguageModelChat } from 'vscode'; -import { createRequestHMAC } from '../../../util/common/crypto'; import { TaskSingler } from '../../../util/common/taskSingler'; import { Emitter, Event } from '../../../util/vs/base/common/event'; import { Disposable } from '../../../util/vs/base/common/lifecycle'; import { generateUuid } from '../../../util/vs/base/common/uuid'; +import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation'; import { IAuthenticationService } from '../../authentication/common/authentication'; import { ConfigKey, IConfigurationService } from '../../configuration/common/configurationService'; import { IEnvService } from '../../env/common/envService'; import { ILogService } from '../../log/common/logService'; -import { IFetcherService } from '../../networking/common/fetcherService'; import { getRequest } from '../../networking/common/networking'; import { IRequestLogger } from '../../requestLogger/node/requestLogger'; import { IExperimentationService } from '../../telemetry/common/nullExperimentationService'; -import { ITelemetryService } from '../../telemetry/common/telemetry'; -import { ICAPIClientService } from '../common/capiClient'; import { ChatEndpointFamily, IChatModelInformation, ICompletionModelInformation, IEmbeddingModelInformation, IModelAPIResponse, isChatModelInformation, isCompletionModelInformation, isEmbeddingModelInformation } from '../common/endpointProvider'; import { ModelAliasRegistry } from '../common/modelAliasRegistry'; @@ -83,15 +80,13 @@ export class ModelMetadataFetcher extends Disposable implements IModelMetadataFe constructor( protected readonly _isModelLab: boolean, - @IFetcherService private readonly _fetcher: IFetcherService, @IRequestLogger private readonly _requestLogger: IRequestLogger, - @ICAPIClientService private readonly _capiClientService: ICAPIClientService, @IConfigurationService private readonly _configService: IConfigurationService, @IExperimentationService private readonly _expService: IExperimentationService, @IEnvService private readonly _envService: IEnvService, @IAuthenticationService private readonly _authService: IAuthenticationService, - @ITelemetryService private readonly _telemetryService: ITelemetryService, @ILogService private readonly _logService: ILogService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { super(); this._register(this._authService.onDidAuthenticationChange(() => { @@ -241,16 +236,12 @@ export class ModelMetadataFetcher extends Disposable implements IModelMetadataFe const requestMetadata = { type: RequestType.Models, isModelLab: this._isModelLab }; try { - const response = await getRequest( - this._fetcher, - this._telemetryService, - this._capiClientService, - requestMetadata, - copilotToken, - await createRequestHMAC(process.env.HMAC_SECRET), - 'model-access', + const response = await this._instantiationService.invokeFunction(getRequest, { + endpointOrUrl: requestMetadata, + secretKey: copilotToken, + intent: 'model-access', requestId, - ); + }); this._lastFetchTime = Date.now(); this._logService.info(`Fetched model metadata in ${Date.now() - requestStartTime}ms ${requestId}`); diff --git a/extensions/copilot/src/platform/endpoint/test/node/testEndpointProvider.ts b/extensions/copilot/src/platform/endpoint/test/node/testEndpointProvider.ts index 1c11c7d0c9e..f62f4b05436 100644 --- a/extensions/copilot/src/platform/endpoint/test/node/testEndpointProvider.ts +++ b/extensions/copilot/src/platform/endpoint/test/node/testEndpointProvider.ts @@ -18,12 +18,9 @@ import { CHAT_MODEL, IConfigurationService } from '../../../configuration/common import { LEGACY_EMBEDDING_MODEL_ID } from '../../../embeddings/common/embeddingsComputer'; import { IEnvService } from '../../../env/common/envService'; import { ILogService } from '../../../log/common/logService'; -import { IFetcherService } from '../../../networking/common/fetcherService'; import { IChatEndpoint, IEmbeddingsEndpoint } from '../../../networking/common/networking'; import { IRequestLogger } from '../../../requestLogger/node/requestLogger'; import { IExperimentationService } from '../../../telemetry/common/nullExperimentationService'; -import { ITelemetryService } from '../../../telemetry/common/telemetry'; -import { ICAPIClientService } from '../../common/capiClient'; import { ChatEndpointFamily, EmbeddingsEndpointFamily, IChatModelInformation, ICompletionModelInformation, IEmbeddingModelInformation, IEndpointProvider } from '../../common/endpointProvider'; import { EmbeddingEndpoint } from '../../node/embeddingsEndpoint'; import { ModelMetadataFetcher } from '../../node/modelMetadataFetcher'; @@ -69,27 +66,23 @@ export class TestModelMetadataFetcher extends ModelMetadataFetcher { _isModelLab: boolean, info: CurrentTestRunInfo | undefined, private readonly _skipModelMetadataCache: boolean = false, - @IFetcherService _fetcher: IFetcherService, - @ICAPIClientService _capiClientService: ICAPIClientService, @IConfigurationService _configService: IConfigurationService, @IExperimentationService _expService: IExperimentationService, @IEnvService _envService: IEnvService, @IAuthenticationService _authService: IAuthenticationService, - @ITelemetryService _telemetryService: ITelemetryService, @ILogService _logService: ILogService, @IRequestLogger _requestLogger: IRequestLogger, + @IInstantiationService _instantiationService: IInstantiationService, ) { super( _isModelLab, - _fetcher, _requestLogger, - _capiClientService, _configService, _expService, _envService, _authService, - _telemetryService, _logService, + _instantiationService, ); this.cache = new SQLiteCache('modelMetadata', TestingCacheSalts.modelMetadata, info); diff --git a/extensions/copilot/src/platform/networking/common/networking.ts b/extensions/copilot/src/platform/networking/common/networking.ts index 2d00c08ea5d..547f61b2e34 100644 --- a/extensions/copilot/src/platform/networking/common/networking.ts +++ b/extensions/copilot/src/platform/networking/common/networking.ts @@ -10,6 +10,7 @@ import { createServiceIdentifier } from '../../../util/common/services'; import { ITokenizer, TokenizerType } from '../../../util/common/tokenizer'; import { AsyncIterableObject } from '../../../util/vs/base/common/async'; import { CancellationError } from '../../../util/vs/base/common/errors'; +import { ServicesAccessor } from '../../../util/vs/platform/instantiation/common/instantiation'; import { Source } from '../../chat/common/chatMLFetcher'; import type { ChatLocation, ChatResponse } from '../../chat/common/commonTypes'; import { ICAPIClientService } from '../../endpoint/common/capiClient'; @@ -303,22 +304,29 @@ export function createCapiRequestBody(options: ICreateEndpointBodyOptions, model return request; } +export interface INetworkRequestOptions { + readonly requestType: 'GET' | 'POST'; + readonly endpointOrUrl: IEndpoint | string | RequestMetadata; + readonly secretKey: string; + readonly intent: string; + readonly requestId: string; + readonly body?: IEndpointBody; + readonly additionalHeaders?: Record; + readonly cancelToken?: CancellationToken; + readonly useFetcher?: FetcherId; + readonly canRetryOnce?: boolean; + readonly location?: ChatLocation; +} + function networkRequest( - fetcher: IFetcher, - telemetryService: ITelemetryService, - capiClientService: ICAPIClientService, - requestType: 'GET' | 'POST', - endpointOrUrl: IEndpoint | string | RequestMetadata, - secretKey: string, - intent: string, - requestId: string, - body?: IEndpointBody, - additionalHeaders?: Record, - cancelToken?: CancellationToken, - useFetcher?: FetcherId, - canRetryOnce: boolean = true, - location?: ChatLocation, + accessor: ServicesAccessor, + options: INetworkRequestOptions, ): Promise { + const fetcher = accessor.get(IFetcherService); + const telemetryService = accessor.get(ITelemetryService); + const capiClientService = accessor.get(ICAPIClientService); + const { requestType, endpointOrUrl, secretKey, intent, requestId, body, additionalHeaders, cancelToken, useFetcher, canRetryOnce = true, location } = options; + // TODO @lramos15 Eventually don't even construct this fake endpoint object. const endpoint = typeof endpointOrUrl === 'string' || 'type' in endpointOrUrl ? { modelMaxPromptTokens: 0, @@ -401,63 +409,17 @@ export function canRetryOnceNetworkError(reason: any) { } export function postRequest( - fetcherService: IFetcherService, - telemetryService: ITelemetryService, - capiClientService: ICAPIClientService, - endpointOrUrl: IEndpoint | string | RequestMetadata, - secretKey: string, - hmac: string | undefined, - intent: string, - requestId: string, - body?: IEndpointBody, - additionalHeaders?: Record, - cancelToken?: CancellationToken, - useFetcher?: FetcherId, - canRetryOnce: boolean = true, - location?: ChatLocation, + accessor: ServicesAccessor, + options: Omit, ): Promise { - return networkRequest(fetcherService, - telemetryService, - capiClientService, - 'POST', - endpointOrUrl, - secretKey, - intent, - requestId, - body, - additionalHeaders, - cancelToken, - useFetcher, - canRetryOnce, - location, - ); + return networkRequest(accessor, { ...options, requestType: 'POST' }); } export function getRequest( - fetcherService: IFetcher, - telemetryService: ITelemetryService, - capiClientService: ICAPIClientService, - endpointOrUrl: IEndpoint | string | RequestMetadata, - secretKey: string, - hmac: string | undefined, - intent: string, - requestId: string, - body?: IEndpointBody, - additionalHeaders?: Record, - cancelToken?: CancellationToken + accessor: ServicesAccessor, + options: Omit, ): Promise { - return networkRequest(fetcherService, - telemetryService, - capiClientService, - 'GET', - endpointOrUrl, - secretKey, - intent, - requestId, - body, - additionalHeaders, - cancelToken - ); + return networkRequest(accessor, { ...options, requestType: 'GET' }); } export const IHeaderContributors = createServiceIdentifier('headerContributors'); diff --git a/extensions/copilot/src/platform/networking/test/node/networking.spec.ts b/extensions/copilot/src/platform/networking/test/node/networking.spec.ts index 5658a1a0d5b..eeb0804f35a 100644 --- a/extensions/copilot/src/platform/networking/test/node/networking.spec.ts +++ b/extensions/copilot/src/platform/networking/test/node/networking.spec.ts @@ -6,8 +6,7 @@ import { RequestType } from '@vscode/copilot-api'; import assert from 'assert'; import { suite, test } from 'vitest'; -import { ICAPIClientService } from '../../../endpoint/common/capiClient'; -import { ITelemetryService } from '../../../telemetry/common/telemetry'; +import { IInstantiationService } from '../../../../util/vs/platform/instantiation/common/instantiation'; import { createFakeResponse } from '../../../test/node/fetcher'; import { createPlatformServices } from '../../../test/node/services'; import { FetchOptions, IAbortController, IFetcherService, PaginationOptions, Response } from '../../common/fetcherService'; @@ -57,16 +56,12 @@ suite('Networking test Suite', function () { const testingServiceCollection = createPlatformServices(); testingServiceCollection.define(IFetcherService, new StaticFetcherService()); const accessor = testingServiceCollection.createTestingAccessor(); - await postRequest( - accessor.get(IFetcherService), - accessor.get(ITelemetryService), - accessor.get(ICAPIClientService), - { type: RequestType.Models }, - '', - '', - 'test', - 'id' - ); + await accessor.get(IInstantiationService).invokeFunction(postRequest, { + endpointOrUrl: { type: RequestType.Models }, + secretKey: '', + intent: 'test', + requestId: 'id', + }); assert.strictEqual(headerBuffer!['VScode-SessionId'], 'test-session'); assert.strictEqual(headerBuffer!['VScode-MachineId'], 'test-machine'); diff --git a/extensions/copilot/src/platform/remoteCodeSearch/common/adoCodeSearchService.ts b/extensions/copilot/src/platform/remoteCodeSearch/common/adoCodeSearchService.ts index db47249cfa7..5daed06466d 100644 --- a/extensions/copilot/src/platform/remoteCodeSearch/common/adoCodeSearchService.ts +++ b/extensions/copilot/src/platform/remoteCodeSearch/common/adoCodeSearchService.ts @@ -12,20 +12,18 @@ import { Disposable } from '../../../util/vs/base/common/lifecycle'; import { StopWatch } from '../../../util/vs/base/common/stopwatch'; import { URI } from '../../../util/vs/base/common/uri'; import { Range } from '../../../util/vs/editor/common/core/range'; -import { createDecorator } from '../../../util/vs/platform/instantiation/common/instantiation'; +import { createDecorator, IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation'; import { IAuthenticationService } from '../../authentication/common/authentication'; import { FileChunkAndScore } from '../../chunking/common/chunk'; import { getGithubMetadataHeaders } from '../../chunking/common/chunkingEndpointClientImpl'; import { stripChunkTextMetadata } from '../../chunking/common/chunkingStringUtils'; import { ConfigKey, IConfigurationService } from '../../configuration/common/configurationService'; import { EmbeddingType } from '../../embeddings/common/embeddingsComputer'; -import { ICAPIClientService } from '../../endpoint/common/capiClient'; import { IEnvService } from '../../env/common/envService'; import { AdoRepoId } from '../../git/common/gitService'; import { IIgnoreService } from '../../ignore/common/ignoreService'; import { measureExecTime } from '../../log/common/logExecTime'; import { ILogService } from '../../log/common/logService'; -import { IFetcherService } from '../../networking/common/fetcherService'; import { getRequest, postRequest } from '../../networking/common/networking'; import { ITelemetryService } from '../../telemetry/common/telemetry'; import { CodeSearchOptions, CodeSearchResult, RemoteCodeSearchError, RemoteCodeSearchIndexState, RemoteCodeSearchIndexStatus } from './remoteCodeSearch'; @@ -120,12 +118,11 @@ export class AdoCodeSearchService extends Disposable implements IAdoCodeSearchSe constructor( @IAuthenticationService private readonly _authenticationService: IAuthenticationService, @IConfigurationService private readonly _configurationService: IConfigurationService, - @ICAPIClientService private readonly _capiClientService: ICAPIClientService, @IEnvService private readonly _envService: IEnvService, @ILogService private readonly _logService: ILogService, - @IFetcherService private readonly _fetcherService: IFetcherService, @IIgnoreService private readonly _ignoreService: IIgnoreService, @ITelemetryService private readonly _telemetryService: ITelemetryService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { super(); } @@ -177,18 +174,14 @@ export class AdoCodeSearchService extends Disposable implements IAdoCodeSearchSe }; const result = await raceCancellationError( - getRequest( - this._fetcherService, - this._telemetryService, - this._capiClientService, - endpoint, - authToken, - undefined, - 'copilot-panel', - '', - undefined, + this._instantiationService.invokeFunction(getRequest, { + endpointOrUrl: endpoint, + secretKey: authToken, + intent: 'copilot-panel', + requestId: '', additionalHeaders, - token), + cancelToken: token, + }), token); if (!result.ok) { @@ -277,16 +270,12 @@ export class AdoCodeSearchService extends Disposable implements IAdoCodeSearchSe const requestSw = new StopWatch(); const response = await raceCancellationError( - postRequest( - this._fetcherService, - this._telemetryService, - this._capiClientService, - endpoint, - authToken, - undefined, - 'copilot-panel', - '', - { + this._instantiationService.invokeFunction(postRequest, { + endpointOrUrl: endpoint, + secretKey: authToken, + intent: 'copilot-panel', + requestId: '', + body: { // TODO: Unclear what's ADO's actual limit is prompt: searchQuery.slice(0, 10000), scoping_query: `repo:${repo.adoRepoId.project}/${repo.adoRepoId.repo}`, @@ -297,7 +286,8 @@ export class AdoCodeSearchService extends Disposable implements IAdoCodeSearchSe limit: number; }, additionalHeaders, - token), + cancelToken: token, + }), token); const requestExecTime = requestSw.elapsed(); diff --git a/extensions/copilot/src/platform/remoteCodeSearch/common/githubCodeSearchService.ts b/extensions/copilot/src/platform/remoteCodeSearch/common/githubCodeSearchService.ts index dded6367deb..2f8e800c39e 100644 --- a/extensions/copilot/src/platform/remoteCodeSearch/common/githubCodeSearchService.ts +++ b/extensions/copilot/src/platform/remoteCodeSearch/common/githubCodeSearchService.ts @@ -3,17 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { RequestType } from '@vscode/copilot-api'; -import { createRequestHMAC } from '../../../util/common/crypto'; import { shouldInclude } from '../../../util/common/glob'; import { Result } from '../../../util/common/result'; import { TelemetryCorrelationId } from '../../../util/common/telemetryCorrelationId'; import { raceCancellationError } from '../../../util/vs/base/common/async'; import { CancellationToken } from '../../../util/vs/base/common/cancellation'; import { isCancellationError } from '../../../util/vs/base/common/errors'; -import { env } from '../../../util/vs/base/common/process'; import { URI } from '../../../util/vs/base/common/uri'; import { Range } from '../../../util/vs/editor/common/core/range'; -import { createDecorator } from '../../../util/vs/platform/instantiation/common/instantiation'; +import { createDecorator, IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation'; import { IAuthenticationService } from '../../authentication/common/authentication'; import { FileChunkAndScore } from '../../chunking/common/chunk'; import { getGithubMetadataHeaders } from '../../chunking/common/chunkingEndpointClientImpl'; @@ -24,7 +22,7 @@ import { IEnvService } from '../../env/common/envService'; import { GithubRepoId, toGithubNwo } from '../../git/common/gitService'; import { IIgnoreService } from '../../ignore/common/ignoreService'; import { ILogService } from '../../log/common/logService'; -import { IFetcherService, Response } from '../../networking/common/fetcherService'; +import { Response } from '../../networking/common/fetcherService'; import { postRequest } from '../../networking/common/networking'; import { ITelemetryService } from '../../telemetry/common/telemetry'; import { CodeSearchOptions, CodeSearchResult, RemoteCodeSearchError, RemoteCodeSearchIndexState, RemoteCodeSearchIndexStatus } from './remoteCodeSearch'; @@ -110,10 +108,10 @@ export class GithubCodeSearchService implements IGithubCodeSearchService { @IAuthenticationService private readonly _authenticationService: IAuthenticationService, @ICAPIClientService private readonly _capiClientService: ICAPIClientService, @IEnvService private readonly _envService: IEnvService, - @IFetcherService private readonly _fetcherService: IFetcherService, @IIgnoreService private readonly _ignoreService: IIgnoreService, @ILogService private readonly _logService: ILogService, @ITelemetryService private readonly _telemetryService: ITelemetryService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { } async getRemoteIndexState(auth: { readonly silent: boolean }, githubRepoId: GithubRepoId, token: CancellationToken): Promise> { @@ -267,16 +265,12 @@ export class GithubCodeSearchService implements IGithubCodeSearchService { } const response = await raceCancellationError( - postRequest( - this._fetcherService, - this._telemetryService, - this._capiClientService, - { type: RequestType.EmbeddingsCodeSearch }, - authToken, - await createRequestHMAC(env.HMAC_SECRET), - 'copilot-panel', - '', - { + this._instantiationService.invokeFunction(postRequest, { + endpointOrUrl: { type: RequestType.EmbeddingsCodeSearch }, + secretKey: authToken, + intent: 'copilot-panel', + requestId: '', + body: { scoping_query: `repo:${toGithubNwo(repo.githubRepoId)}`, // The semantic search endpoint only supports prompts of up to 8k bytes (in utf8) // For now just truncate but we should consider a better way to handle this, such as having a model @@ -292,8 +286,9 @@ export class GithubCodeSearchService implements IGithubCodeSearchService { limit: number; embedding_model: string; } as any, - getGithubMetadataHeaders(telemetryInfo.callTracker, this._envService), - token), + additionalHeaders: getGithubMetadataHeaders(telemetryInfo.callTracker, this._envService), + cancelToken: token, + }), token); if (!response.ok) { diff --git a/extensions/copilot/src/platform/remoteSearch/node/codeOrDocsSearchClientImpl.ts b/extensions/copilot/src/platform/remoteSearch/node/codeOrDocsSearchClientImpl.ts index d923900f1b3..4321bdc1ef6 100644 --- a/extensions/copilot/src/platform/remoteSearch/node/codeOrDocsSearchClientImpl.ts +++ b/extensions/copilot/src/platform/remoteSearch/node/codeOrDocsSearchClientImpl.ts @@ -3,16 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { RequestMetadata, RequestType } from '@vscode/copilot-api'; -import { createRequestHMAC } from '../../../util/common/crypto'; import { TokenizerType } from '../../../util/common/tokenizer'; import { CancellationToken } from '../../../util/vs/base/common/cancellation'; import { CancellationError, isCancellationError } from '../../../util/vs/base/common/errors'; import { generateUuid } from '../../../util/vs/base/common/uuid'; +import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation'; import { IAuthenticationService } from '../../authentication/common/authentication'; -import { ICAPIClientService } from '../../endpoint/common/capiClient'; import { LogExecTime } from '../../log/common/logExecTime'; import { ILogService } from '../../log/common/logService'; -import { IFetcherService } from '../../networking/common/fetcherService'; import { IEndpoint, postRequest } from '../../networking/common/networking'; import { ITelemetryService } from '../../telemetry/common/telemetry'; import { ICodeOrDocsSearchBaseScopingQuery, ICodeOrDocsSearchItem, ICodeOrDocsSearchMultiRepoScopingQuery, ICodeOrDocsSearchOptions, ICodeOrDocsSearchResult, ICodeOrDocsSearchSingleRepoScopingQuery, IDocsSearchClient } from '../common/codeOrDocsSearchClient'; @@ -55,11 +53,10 @@ export class DocsSearchClient implements IDocsSearchClient { private readonly slug = 'docs'; constructor( - @ICAPIClientService private readonly _capiClientService: ICAPIClientService, @ITelemetryService private readonly _telemetryService: ITelemetryService, @IAuthenticationService private readonly _authenticationService: IAuthenticationService, - @IFetcherService private readonly _fetcherService: IFetcherService, @ILogService private readonly _logService: ILogService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { } search(query: string, scopingQuery: ICodeOrDocsSearchSingleRepoScopingQuery, options?: ICodeOrDocsSearchOptions, token?: CancellationToken): Promise; @@ -192,24 +189,19 @@ export class DocsSearchClient implements IDocsSearchClient { return headers; }, }; - const response = await postRequest( - this._fetcherService, - this._telemetryService, - this._capiClientService, - endpointInfo, - authToken ?? '', - await createRequestHMAC(process.env.HMAC_SECRET), - 'codesearch', - generateUuid(), - { + const response = await this._instantiationService.invokeFunction(postRequest, { + endpointOrUrl: endpointInfo, + secretKey: authToken ?? '', + intent: 'codesearch', + requestId: generateUuid(), + body: { query, scopingQuery: formatScopingQuery(scopingQuery), similarity, limit }, - undefined, - cancellationToken - ); + cancelToken: cancellationToken, + }); const text = await response.text(); if (response.status === 404 || (response.status === 400 && text.includes('unknown integration'))) { diff --git a/extensions/copilot/src/platform/workspaceChunkSearch/common/githubAvailableEmbeddingTypes.ts b/extensions/copilot/src/platform/workspaceChunkSearch/common/githubAvailableEmbeddingTypes.ts index ba91af1a4e1..33fbe614af2 100644 --- a/extensions/copilot/src/platform/workspaceChunkSearch/common/githubAvailableEmbeddingTypes.ts +++ b/extensions/copilot/src/platform/workspaceChunkSearch/common/githubAvailableEmbeddingTypes.ts @@ -4,20 +4,18 @@ *--------------------------------------------------------------------------------------------*/ import { RequestType } from '@vscode/copilot-api'; -import { createRequestHMAC } from '../../../util/common/crypto'; import { Result } from '../../../util/common/result'; import { createServiceIdentifier } from '../../../util/common/services'; import { CallTracker } from '../../../util/common/telemetryCorrelationId'; -import { env } from '../../../util/vs/base/common/process'; import { generateUuid } from '../../../util/vs/base/common/uuid'; +import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation'; import { IAuthenticationService } from '../../authentication/common/authentication'; import { getGithubMetadataHeaders } from '../../chunking/common/chunkingEndpointClientImpl'; import { ConfigKey, IConfigurationService } from '../../configuration/common/configurationService'; import { EmbeddingType } from '../../embeddings/common/embeddingsComputer'; -import { ICAPIClientService } from '../../endpoint/common/capiClient'; import { IEnvService } from '../../env/common/envService'; import { ILogService } from '../../log/common/logService'; -import { IFetcherService, Response } from '../../networking/common/fetcherService'; +import { Response } from '../../networking/common/fetcherService'; import { getRequest } from '../../networking/common/networking'; import { IExperimentationService } from '../../telemetry/common/nullExperimentationService'; import { ITelemetryService } from '../../telemetry/common/telemetry'; @@ -59,11 +57,10 @@ export class GithubAvailableEmbeddingTypesService implements IGithubAvailableEmb @ILogService private readonly _logService: ILogService, @IAuthenticationService private readonly _authService: IAuthenticationService, @ITelemetryService private readonly _telemetryService: ITelemetryService, - @ICAPIClientService private readonly _capiClientService: ICAPIClientService, @IEnvService private readonly _envService: IEnvService, - @IFetcherService private readonly _fetcherService: IFetcherService, @IConfigurationService private readonly _configurationService: IConfigurationService, @IExperimentationService private readonly _experimentationService: IExperimentationService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { this._cached = this._authService.getGitHubSession('any', { silent: true }).then(session => { if (!session) { @@ -115,18 +112,13 @@ export class GithubAvailableEmbeddingTypesService implements IGithubAvailableEmb private async doGetAvailableTypes(token: string): Promise { let response: Response; try { - response = await getRequest( - this._fetcherService, - this._telemetryService, - this._capiClientService, - { type: RequestType.EmbeddingsModels }, - token, - await createRequestHMAC(env.HMAC_SECRET), - 'copilot-panel', - generateUuid(), - undefined, - getGithubMetadataHeaders(new CallTracker(), this._envService) - ); + response = await this._instantiationService.invokeFunction(getRequest, { + endpointOrUrl: { type: RequestType.EmbeddingsModels }, + secretKey: token, + intent: 'copilot-panel', + requestId: generateUuid(), + additionalHeaders: getGithubMetadataHeaders(new CallTracker(), this._envService), + }); } catch (e) { this._logService.error('Error fetching available embedding types', e); return Result.error({ diff --git a/extensions/copilot/test/base/cachingEmbeddingsFetcher.ts b/extensions/copilot/test/base/cachingEmbeddingsFetcher.ts index c422edb2721..5246e8a5570 100644 --- a/extensions/copilot/test/base/cachingEmbeddingsFetcher.ts +++ b/extensions/copilot/test/base/cachingEmbeddingsFetcher.ts @@ -6,13 +6,12 @@ import type { CancellationToken } from 'vscode'; import { IAuthenticationService } from '../../src/platform/authentication/common/authentication'; import { ComputeEmbeddingsOptions, Embedding, EmbeddingType, EmbeddingVector, Embeddings, LEGACY_EMBEDDING_MODEL_ID, getWellKnownEmbeddingTypeInfo } from '../../src/platform/embeddings/common/embeddingsComputer'; import { RemoteEmbeddingsComputer } from '../../src/platform/embeddings/common/remoteEmbeddingsComputer'; -import { ICAPIClientService } from '../../src/platform/endpoint/common/capiClient'; import { IEndpointProvider } from '../../src/platform/endpoint/common/endpointProvider'; import { IEnvService } from '../../src/platform/env/common/envService'; import { ILogService } from '../../src/platform/log/common/logService'; -import { IFetcherService } from '../../src/platform/networking/common/fetcherService'; import { ITelemetryService } from '../../src/platform/telemetry/common/telemetry'; import { TelemetryCorrelationId } from '../../src/util/common/telemetryCorrelationId'; +import { IInstantiationService } from '../../src/util/vs/platform/instantiation/common/instantiation'; import { computeSHA256 } from './hash'; export class CacheableEmbeddingRequest { @@ -46,21 +45,19 @@ export class CachingEmbeddingsComputer extends RemoteEmbeddingsComputer { constructor( private readonly cache: IEmbeddingsCache, @IAuthenticationService authService: IAuthenticationService, - @ICAPIClientService capiClientService: ICAPIClientService, @IEnvService envService: IEnvService, - @IFetcherService fetcherService: IFetcherService, @ILogService logService: ILogService, @ITelemetryService telemetryService: ITelemetryService, - @IEndpointProvider endpointProvider: IEndpointProvider + @IEndpointProvider endpointProvider: IEndpointProvider, + @IInstantiationService instantiationService: IInstantiationService, ) { super( authService, - capiClientService, envService, - fetcherService, logService, telemetryService, - endpointProvider + endpointProvider, + instantiationService, ); }