Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/prompts/node/inline/languageServerContextPrompt.tsx
13405 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { PromptElement, PromptElementProps, type PromptSizing } from '@vscode/prompt-tsx';
7
import type { CancellationToken, ChatResponsePart, Position, Progress } from 'vscode';
8
import { ConfigKey, IConfigurationService } from '../../../../platform/configuration/common/configurationService';
9
import { TextDocumentSnapshot } from '../../../../platform/editing/common/textDocumentSnapshot';
10
import { IIgnoreService } from '../../../../platform/ignore/common/ignoreService';
11
import { ContextKind, ILanguageContextService, KnownSources, SnippetContext, type RequestContext } from '../../../../platform/languageServer/common/languageContextService';
12
import { IExperimentationService } from '../../../../platform/telemetry/common/nullExperimentationService';
13
import { Iterable } from '../../../../util/vs/base/common/iterator';
14
import { TelemetryData } from '../../../prompt/node/intents';
15
import { Tag } from '../base/tag';
16
import { CodeBlock, Uri as UriElement, UriMode } from '../panel/safeElements';
17
18
19
export type LanguageServerContextProps = PromptElementProps<{
20
/**
21
* The text document to get context for.
22
*/
23
document: TextDocumentSnapshot;
24
25
/**
26
* The position in the document to get context for.
27
*/
28
position: Position;
29
30
/**
31
* The request id for the context.
32
*/
33
requestId?: string;
34
35
/**
36
* The source of the request.
37
*/
38
source?: KnownSources | string;
39
}>;
40
41
42
export class LanguageServerContextStats extends TelemetryData {
43
constructor(
44
readonly snippetCounts: number,
45
readonly totalCharLength: number,
46
) {
47
super();
48
}
49
}
50
51
export class LanguageServerContextPrompt extends PromptElement<LanguageServerContextProps> {
52
53
private static CompletionContext: RequestContext = {
54
requestId: '0013686c-f799-4ed9-ad07-35369dbd6e26',
55
timeBudget: 2500,
56
tokenBudget: 32_000,
57
};
58
59
constructor(
60
props: LanguageServerContextProps,
61
@ILanguageContextService private readonly languageContextService: ILanguageContextService,
62
@IConfigurationService private readonly configurationService: IConfigurationService,
63
@IExperimentationService private readonly experimentationService: IExperimentationService,
64
@IIgnoreService private readonly ignoreService: IIgnoreService
65
66
) {
67
super(props);
68
}
69
70
async render(_state: void, sizing: PromptSizing, _progress: Progress<ChatResponsePart>, token: CancellationToken) {
71
72
const configKey = this.props.source === KnownSources.chat
73
? ConfigKey.TypeScriptLanguageContextInline
74
: this.props.source === KnownSources.fix
75
? ConfigKey.TypeScriptLanguageContextFix
76
: undefined;
77
78
if (configKey === undefined) {
79
return;
80
}
81
const useLanguageServerContext = this.configurationService.getExperimentBasedConfig(configKey, this.experimentationService);
82
if (!useLanguageServerContext) {
83
return;
84
}
85
86
if (!await this.languageContextService.isActivated(this.props.document.languageId)) {
87
return;
88
}
89
90
const context: RequestContext = Object.assign({}, LanguageServerContextPrompt.CompletionContext, { tokenBudget: sizing.tokenBudget });
91
if (this.props.requestId !== undefined) {
92
context.requestId = this.props.requestId;
93
}
94
if (this.props.source !== undefined) {
95
context.source = this.props.source;
96
}
97
98
const validItems: SnippetContext[] = [];
99
const contextItems = this.languageContextService.getContext(this.props.document.document, this.props.position, context, token);
100
outer: for await (const item of contextItems) {
101
if (item.kind === ContextKind.Snippet) {
102
if (item.value.length === 0) {
103
continue;
104
}
105
if (await this.ignoreService.isCopilotIgnored(item.uri)) {
106
continue;
107
}
108
if (item.additionalUris !== undefined && item.additionalUris.length > 0) {
109
for (const uri of item.additionalUris) {
110
if (await this.ignoreService.isCopilotIgnored(uri)) {
111
continue outer;
112
}
113
}
114
}
115
validItems.push(item);
116
}
117
}
118
if (validItems.length === 0) {
119
return;
120
}
121
122
return <Tag name='languageServerContext'>
123
A language server finds these documents helpful for answering the user's question<br />
124
<Tag name='note'>
125
These documents are provided as extra insights but are not meant to be edited or changed in any way.
126
</Tag>
127
{
128
validItems.map(item => {
129
return <>
130
<Tag name='documentFragment'>
131
From `<UriElement value={item.uri} mode={UriMode.Path} />` I have read or edited:<br />
132
<CodeBlock uri={item.uri} code={item.value} priority={item.priority * Number.MAX_SAFE_INTEGER} />
133
</Tag>
134
<br />
135
</>;
136
})
137
}
138
<meta value={new LanguageServerContextStats(
139
validItems.length,
140
Iterable.reduce(validItems.values(), (t, item) => t + item.value.length, 0))
141
} />
142
</Tag>;
143
}
144
}
145
146