Path: blob/main/extensions/copilot/src/extension/context/node/resolvers/extensionApi.tsx
13405 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/4import { BasePromptElementProps, PromptElement, PromptPiece, PromptSizing, TextChunk } from '@vscode/prompt-tsx';5import { ChatResponsePart } from '@vscode/prompt-tsx/dist/base/vscodeTypes';6import { Embedding, EmbeddingType, EmbeddingVector, IEmbeddingsComputer, rankEmbeddings } from '../../../../platform/embeddings/common/embeddingsComputer';7import { EmbeddingCacheType, IEmbeddingsCache, LocalEmbeddingsCache, RemoteCacheType, RemoteEmbeddingsCache } from '../../../../platform/embeddings/common/embeddingsIndex';8import { IEnvService } from '../../../../platform/env/common/envService';9import { Progress } from '../../../../platform/notification/common/notificationService';10import { createFencedCodeBlock } from '../../../../util/common/markdown';11import { TelemetryCorrelationId } from '../../../../util/common/telemetryCorrelationId';12import { sanitizeVSCodeVersion } from '../../../../util/common/vscodeVersion';13import { CancellationToken } from '../../../../util/vs/base/common/cancellation';14import { createDecorator, IInstantiationService } from '../../../../util/vs/platform/instantiation/common/instantiation';1516type BaseApiContext = { text: string; embedding: EmbeddingVector; type: 'code' | 'command' | 'documentationCodeBlock' };17type CodeApiContext = BaseApiContext & { type: 'code'; lang: string };18type CommandApiContext = BaseApiContext & { type: 'command' };19type DocumentationCodeBlockApiContext = BaseApiContext & { type: 'documentationCodeBlock'; lang: string };20type ApiContext = CodeApiContext | CommandApiContext | DocumentationCodeBlockApiContext;2122export class ApiEmbeddingsIndex implements IApiEmbeddingsIndex {23declare readonly _serviceBrand: undefined;24private readonly embeddingsCache: IEmbeddingsCache;25private apiChunks: ApiContext[] | undefined;2627constructor(28useRemoteCache: boolean = true,29@IEnvService envService: IEnvService,30@IInstantiationService instantiationService: IInstantiationService31) {32const cacheVersion = sanitizeVSCodeVersion(envService.getEditorInfo().version);33this.embeddingsCache = useRemoteCache ?34instantiationService.createInstance(RemoteEmbeddingsCache, EmbeddingCacheType.GLOBAL, 'api', cacheVersion, EmbeddingType.text3small_512, RemoteCacheType.Api) :35instantiationService.createInstance(LocalEmbeddingsCache, EmbeddingCacheType.GLOBAL, 'api', cacheVersion, EmbeddingType.text3small_512);36}3738async updateIndex(): Promise<void> {39this.apiChunks = await this.embeddingsCache.getCache();40}4142public nClosestValues(queryEmbedding: Embedding, n: number): string[] {43if (!this.apiChunks) {44return [];45}4647return rankEmbeddings(queryEmbedding, this.apiChunks.map(item => [item, { type: this.embeddingsCache.embeddingType, value: item.embedding } satisfies Embedding]), n)48.map(x => this.toContextString(x.value));49}5051private toContextString(context: ApiContext): string {52if (context.type === 'code') {53return `API Reference Code Snippet from vscode.d.ts:\n${createFencedCodeBlock(context.lang, context.text)}`;54} else if (context.type === 'command') {55return `${context.text}`;56} else if (context.type === 'documentationCodeBlock') {57return `Example code from VS Code documentation:\n${createFencedCodeBlock(context.lang, context.text)}`;58}5960return '';61}62}6364export interface IApiEmbeddingsIndex {65readonly _serviceBrand: undefined;6667updateIndex(): Promise<void>;68nClosestValues(embedding: Embedding, n: number): string[];69}7071export const IApiEmbeddingsIndex = createDecorator<IApiEmbeddingsIndex>('IApiEmbeddingsIndex');7273export interface VSCodeAPIContextProps extends BasePromptElementProps {74query: string;75}7677export class VSCodeAPIContextElement extends PromptElement<VSCodeAPIContextProps> {78constructor(79props: VSCodeAPIContextProps,80@IApiEmbeddingsIndex private readonly apiEmbeddingsIndex: IApiEmbeddingsIndex,81@IEmbeddingsComputer private readonly embeddingsComputer: IEmbeddingsComputer,82) {83super(props);84}8586async renderAsString(): Promise<string> {87const snippets = await this.getSnippets(undefined);88return `Below are some potentially relevant code samples related to VS Code extension development. You may use information from these samples to help you answer the question if you believe it is relevant.\n${snippets.join('\n\n')}`;89}9091private async getSnippets(token: CancellationToken | undefined): Promise<string[]> {92await this.apiEmbeddingsIndex.updateIndex();93if (token?.isCancellationRequested) {94return [];95}9697const embeddingResult = await this.embeddingsComputer.computeEmbeddings(EmbeddingType.text3small_512, [this.props.query], {}, new TelemetryCorrelationId('VSCodeAPIContextElement::getSnippets'), token);98return this.apiEmbeddingsIndex.nClosestValues(embeddingResult.values[0], 5);99}100101override async render(state: undefined, sizing: PromptSizing, progress?: Progress<ChatResponsePart>, token?: CancellationToken): Promise<PromptPiece<any, any> | undefined> {102const snippets = await this.getSnippets(token);103if (snippets.length) {104return <>105Below are some potentially relevant code samples related to VS Code extension development. You may use information from these samples to help you answer the question if you believe it is relevant.<br />106{snippets.map(s => {107return <><TextChunk>{s}</TextChunk><br /><br /></>;108})}109</>;110}111}112}113114115