Path: blob/main/extensions/copilot/src/extension/chatSessions/copilotcli/common/delegationSummaryService.ts
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 * as l10n from '@vscode/l10n';6import type { CancellationToken, ChatContext, ChatPromptReference, ChatSummarizer, Uri } from 'vscode';7import { IVSCodeExtensionContext } from '../../../../platform/extContext/common/extensionContext';8import { createServiceIdentifier } from '../../../../util/common/services';9import { Sequencer } from '../../../../util/vs/base/common/async';10import { ResourceMap } from '../../../../util/vs/base/common/map';11import { URI } from '../../../../util/vs/base/common/uri';1213const SummaryFileScheme = 'copilot-delegated-chat-summary';14const DelegationSummaryMementoKey = 'github.copilot.chat.delegationSummary';15export const IChatDelegationSummaryService = createServiceIdentifier<IChatDelegationSummaryService>('IChatDelegationSummaryService');1617export interface IChatDelegationSummaryService {18readonly _serviceBrand: undefined;19scheme: string;20summarize(context: ChatContext, token: CancellationToken): Promise<string | undefined>;21trackSummaryUsage(sessionId: string, summary: string): Promise<ChatPromptReference | undefined>;22extractPrompt(sessionId: string, message: string): { prompt: string; reference: ChatPromptReference } | undefined;23provideTextDocumentContent(uri: Uri): string | undefined;24}252627export class ChatDelegationSummaryService implements IChatDelegationSummaryService {28declare _serviceBrand: undefined;29private readonly _mementoUpdater = new Sequencer();30private readonly _summaries = new ResourceMap<string>();31public readonly scheme = SummaryFileScheme;32constructor(33private readonly _chatSummarizer: ChatSummarizer,34@IVSCodeExtensionContext private readonly context: IVSCodeExtensionContext,35) { }36async summarize(context: ChatContext, token: CancellationToken): Promise<string | undefined> {37return (await this._chatSummarizer.provideChatSummary(context, token)) ?? undefined;38}3940async trackSummaryUsage(sessionId: string, summary: string): Promise<ChatPromptReference | undefined> {41// If summary is less than 100 characters, do not track it, we can display it directly in the chat42if (summary.length < 100) {43return undefined;44}45const uri = URI.from({ scheme: SummaryFileScheme, path: l10n.t("summary"), query: sessionId });46this._summaries.set(uri, summary);47const reference: ChatPromptReference = {48id: uri.toString(),49name: 'Delegation Summary',50modelDescription: 'Summary of previous chat history for delegated request',51value: uri52};5354summary = summary.substring(0, 100);55await this._mementoUpdater.queue(async () => {56const details = this.context.globalState.get<Record<string, { summary: string; createdDateTime: number }>>(DelegationSummaryMementoKey, {});5758details[sessionId] = { summary, createdDateTime: Date.now() };5960// Prune entries older than 7 days.61const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;62for (const [key, value] of Object.entries(details)) {63if (value.createdDateTime < sevenDaysAgo) {64delete details[key];65}66}6768await this.context.globalState.update(DelegationSummaryMementoKey, details);69});7071return reference;72}7374extractPrompt(sessionId: string, message: string): { prompt: string; reference: ChatPromptReference } | undefined {75const details = this.context.globalState.get<Record<string, { summary: string; createdDateTime: number }>>(DelegationSummaryMementoKey, {});76const entry = details[sessionId];77if (!entry) {78return undefined;79}8081const index = message.indexOf(entry.summary);82if (index === -1) {83return undefined;84}85const uri = URI.from({ scheme: SummaryFileScheme, path: l10n.t("summary"), query: sessionId });86const promptSuffix = l10n.t('Complete the task as described in the {0}', `[summary](${uri.toString()})`);87const promptPrefix = message.substring(0, index).trimEnd() || '';88const prompt = promptPrefix ? `${promptPrefix}\n${promptSuffix}` : promptSuffix;89const summary = message.substring(index);90this._summaries.set(uri, summary);91const reference: ChatPromptReference = {92id: uri.toString(),93name: 'Delegation Summary',94modelDescription: 'Summary of previous chat history for delegated request',95value: uri96};9798return { prompt, reference };99}100101102provideTextDocumentContent(uri: Uri): string | undefined {103return this._summaries.get(uri);104}105}106107108