Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/chatSessions/copilotcli/common/delegationSummaryService.ts
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 * as l10n from '@vscode/l10n';
7
import type { CancellationToken, ChatContext, ChatPromptReference, ChatSummarizer, Uri } from 'vscode';
8
import { IVSCodeExtensionContext } from '../../../../platform/extContext/common/extensionContext';
9
import { createServiceIdentifier } from '../../../../util/common/services';
10
import { Sequencer } from '../../../../util/vs/base/common/async';
11
import { ResourceMap } from '../../../../util/vs/base/common/map';
12
import { URI } from '../../../../util/vs/base/common/uri';
13
14
const SummaryFileScheme = 'copilot-delegated-chat-summary';
15
const DelegationSummaryMementoKey = 'github.copilot.chat.delegationSummary';
16
export const IChatDelegationSummaryService = createServiceIdentifier<IChatDelegationSummaryService>('IChatDelegationSummaryService');
17
18
export interface IChatDelegationSummaryService {
19
readonly _serviceBrand: undefined;
20
scheme: string;
21
summarize(context: ChatContext, token: CancellationToken): Promise<string | undefined>;
22
trackSummaryUsage(sessionId: string, summary: string): Promise<ChatPromptReference | undefined>;
23
extractPrompt(sessionId: string, message: string): { prompt: string; reference: ChatPromptReference } | undefined;
24
provideTextDocumentContent(uri: Uri): string | undefined;
25
}
26
27
28
export class ChatDelegationSummaryService implements IChatDelegationSummaryService {
29
declare _serviceBrand: undefined;
30
private readonly _mementoUpdater = new Sequencer();
31
private readonly _summaries = new ResourceMap<string>();
32
public readonly scheme = SummaryFileScheme;
33
constructor(
34
private readonly _chatSummarizer: ChatSummarizer,
35
@IVSCodeExtensionContext private readonly context: IVSCodeExtensionContext,
36
) { }
37
async summarize(context: ChatContext, token: CancellationToken): Promise<string | undefined> {
38
return (await this._chatSummarizer.provideChatSummary(context, token)) ?? undefined;
39
}
40
41
async trackSummaryUsage(sessionId: string, summary: string): Promise<ChatPromptReference | undefined> {
42
// If summary is less than 100 characters, do not track it, we can display it directly in the chat
43
if (summary.length < 100) {
44
return undefined;
45
}
46
const uri = URI.from({ scheme: SummaryFileScheme, path: l10n.t("summary"), query: sessionId });
47
this._summaries.set(uri, summary);
48
const reference: ChatPromptReference = {
49
id: uri.toString(),
50
name: 'Delegation Summary',
51
modelDescription: 'Summary of previous chat history for delegated request',
52
value: uri
53
};
54
55
summary = summary.substring(0, 100);
56
await this._mementoUpdater.queue(async () => {
57
const details = this.context.globalState.get<Record<string, { summary: string; createdDateTime: number }>>(DelegationSummaryMementoKey, {});
58
59
details[sessionId] = { summary, createdDateTime: Date.now() };
60
61
// Prune entries older than 7 days.
62
const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
63
for (const [key, value] of Object.entries(details)) {
64
if (value.createdDateTime < sevenDaysAgo) {
65
delete details[key];
66
}
67
}
68
69
await this.context.globalState.update(DelegationSummaryMementoKey, details);
70
});
71
72
return reference;
73
}
74
75
extractPrompt(sessionId: string, message: string): { prompt: string; reference: ChatPromptReference } | undefined {
76
const details = this.context.globalState.get<Record<string, { summary: string; createdDateTime: number }>>(DelegationSummaryMementoKey, {});
77
const entry = details[sessionId];
78
if (!entry) {
79
return undefined;
80
}
81
82
const index = message.indexOf(entry.summary);
83
if (index === -1) {
84
return undefined;
85
}
86
const uri = URI.from({ scheme: SummaryFileScheme, path: l10n.t("summary"), query: sessionId });
87
const promptSuffix = l10n.t('Complete the task as described in the {0}', `[summary](${uri.toString()})`);
88
const promptPrefix = message.substring(0, index).trimEnd() || '';
89
const prompt = promptPrefix ? `${promptPrefix}\n${promptSuffix}` : promptSuffix;
90
const summary = message.substring(index);
91
this._summaries.set(uri, summary);
92
const reference: ChatPromptReference = {
93
id: uri.toString(),
94
name: 'Delegation Summary',
95
modelDescription: 'Summary of previous chat history for delegated request',
96
value: uri
97
};
98
99
return { prompt, reference };
100
}
101
102
103
provideTextDocumentContent(uri: Uri): string | undefined {
104
return this._summaries.get(uri);
105
}
106
}
107
108