Path: blob/main/extensions/copilot/src/extension/prompts/node/inline/languageServerContextPrompt.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*--------------------------------------------------------------------------------------------*/45import { PromptElement, PromptElementProps, type PromptSizing } from '@vscode/prompt-tsx';6import type { CancellationToken, ChatResponsePart, Position, Progress } from 'vscode';7import { ConfigKey, IConfigurationService } from '../../../../platform/configuration/common/configurationService';8import { TextDocumentSnapshot } from '../../../../platform/editing/common/textDocumentSnapshot';9import { IIgnoreService } from '../../../../platform/ignore/common/ignoreService';10import { ContextKind, ILanguageContextService, KnownSources, SnippetContext, type RequestContext } from '../../../../platform/languageServer/common/languageContextService';11import { IExperimentationService } from '../../../../platform/telemetry/common/nullExperimentationService';12import { Iterable } from '../../../../util/vs/base/common/iterator';13import { TelemetryData } from '../../../prompt/node/intents';14import { Tag } from '../base/tag';15import { CodeBlock, Uri as UriElement, UriMode } from '../panel/safeElements';161718export type LanguageServerContextProps = PromptElementProps<{19/**20* The text document to get context for.21*/22document: TextDocumentSnapshot;2324/**25* The position in the document to get context for.26*/27position: Position;2829/**30* The request id for the context.31*/32requestId?: string;3334/**35* The source of the request.36*/37source?: KnownSources | string;38}>;394041export class LanguageServerContextStats extends TelemetryData {42constructor(43readonly snippetCounts: number,44readonly totalCharLength: number,45) {46super();47}48}4950export class LanguageServerContextPrompt extends PromptElement<LanguageServerContextProps> {5152private static CompletionContext: RequestContext = {53requestId: '0013686c-f799-4ed9-ad07-35369dbd6e26',54timeBudget: 2500,55tokenBudget: 32_000,56};5758constructor(59props: LanguageServerContextProps,60@ILanguageContextService private readonly languageContextService: ILanguageContextService,61@IConfigurationService private readonly configurationService: IConfigurationService,62@IExperimentationService private readonly experimentationService: IExperimentationService,63@IIgnoreService private readonly ignoreService: IIgnoreService6465) {66super(props);67}6869async render(_state: void, sizing: PromptSizing, _progress: Progress<ChatResponsePart>, token: CancellationToken) {7071const configKey = this.props.source === KnownSources.chat72? ConfigKey.TypeScriptLanguageContextInline73: this.props.source === KnownSources.fix74? ConfigKey.TypeScriptLanguageContextFix75: undefined;7677if (configKey === undefined) {78return;79}80const useLanguageServerContext = this.configurationService.getExperimentBasedConfig(configKey, this.experimentationService);81if (!useLanguageServerContext) {82return;83}8485if (!await this.languageContextService.isActivated(this.props.document.languageId)) {86return;87}8889const context: RequestContext = Object.assign({}, LanguageServerContextPrompt.CompletionContext, { tokenBudget: sizing.tokenBudget });90if (this.props.requestId !== undefined) {91context.requestId = this.props.requestId;92}93if (this.props.source !== undefined) {94context.source = this.props.source;95}9697const validItems: SnippetContext[] = [];98const contextItems = this.languageContextService.getContext(this.props.document.document, this.props.position, context, token);99outer: for await (const item of contextItems) {100if (item.kind === ContextKind.Snippet) {101if (item.value.length === 0) {102continue;103}104if (await this.ignoreService.isCopilotIgnored(item.uri)) {105continue;106}107if (item.additionalUris !== undefined && item.additionalUris.length > 0) {108for (const uri of item.additionalUris) {109if (await this.ignoreService.isCopilotIgnored(uri)) {110continue outer;111}112}113}114validItems.push(item);115}116}117if (validItems.length === 0) {118return;119}120121return <Tag name='languageServerContext'>122A language server finds these documents helpful for answering the user's question<br />123<Tag name='note'>124These documents are provided as extra insights but are not meant to be edited or changed in any way.125</Tag>126{127validItems.map(item => {128return <>129<Tag name='documentFragment'>130From `<UriElement value={item.uri} mode={UriMode.Path} />` I have read or edited:<br />131<CodeBlock uri={item.uri} code={item.value} priority={item.priority * Number.MAX_SAFE_INTEGER} />132</Tag>133<br />134</>;135})136}137<meta value={new LanguageServerContextStats(138validItems.length,139Iterable.reduce(validItems.values(), (t, item) => t + item.value.length, 0))140} />141</Tag>;142}143}144145146