Path: blob/main/src/vs/workbench/contrib/chat/common/chatService.ts
3296 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 { IAction } from '../../../../base/common/actions.js';6import { DeferredPromise } from '../../../../base/common/async.js';7import { CancellationToken } from '../../../../base/common/cancellation.js';8import { Event } from '../../../../base/common/event.js';9import { IMarkdownString } from '../../../../base/common/htmlContent.js';10import { IObservable } from '../../../../base/common/observable.js';11import { ThemeIcon } from '../../../../base/common/themables.js';12import { URI } from '../../../../base/common/uri.js';13import { IRange, Range } from '../../../../editor/common/core/range.js';14import { ISelection } from '../../../../editor/common/core/selection.js';15import { Command, Location, TextEdit } from '../../../../editor/common/languages.js';16import { FileType } from '../../../../platform/files/common/files.js';17import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';18import { ICellEditOperation } from '../../notebook/common/notebookCommon.js';19import { IWorkspaceSymbol } from '../../search/common/search.js';20import { IChatAgentCommand, IChatAgentData, IChatAgentResult, UserSelectedTools } from './chatAgents.js';21import { ChatModel, IChatModel, IChatRequestModeInfo, IChatRequestModel, IChatRequestVariableData, IChatResponseModel, IExportableChatData, ISerializableChatData } from './chatModel.js';22import { IParsedChatRequest } from './chatParserTypes.js';23import { IChatParserContext } from './chatRequestParser.js';24import { IChatRequestVariableEntry } from './chatVariableEntries.js';25import { IChatRequestVariableValue } from './chatVariables.js';26import { ChatAgentLocation, ChatModeKind } from './constants.js';27import { IPreparedToolInvocation, IToolConfirmationMessages, IToolResult, IToolResultInputOutputDetails, ToolDataSource } from './languageModelToolsService.js';2829export interface IChatRequest {30message: string;31variables: Record<string, IChatRequestVariableValue[]>;32}3334export enum ChatErrorLevel {35Info = 0,36Warning = 1,37Error = 238}3940export interface IChatResponseErrorDetailsConfirmationButton {41data: any;42label: string;43isSecondary?: boolean;44}4546export interface IChatResponseErrorDetails {47message: string;48responseIsIncomplete?: boolean;49responseIsFiltered?: boolean;50responseIsRedacted?: boolean;51isQuotaExceeded?: boolean;52level?: ChatErrorLevel;53confirmationButtons?: IChatResponseErrorDetailsConfirmationButton[];54code?: string;55}5657export interface IChatResponseProgressFileTreeData {58label: string;59uri: URI;60type?: FileType;61children?: IChatResponseProgressFileTreeData[];62}6364export type IDocumentContext = {65uri: URI;66version: number;67ranges: IRange[];68};6970export function isIDocumentContext(obj: unknown): obj is IDocumentContext {71return (72!!obj &&73typeof obj === 'object' &&74'uri' in obj && obj.uri instanceof URI &&75'version' in obj && typeof obj.version === 'number' &&76'ranges' in obj && Array.isArray(obj.ranges) && obj.ranges.every(Range.isIRange)77);78}7980export interface IChatUsedContext {81documents: IDocumentContext[];82kind: 'usedContext';83}8485export function isIUsedContext(obj: unknown): obj is IChatUsedContext {86return (87!!obj &&88typeof obj === 'object' &&89'documents' in obj &&90Array.isArray(obj.documents) &&91obj.documents.every(isIDocumentContext)92);93}9495export interface IChatContentVariableReference {96variableName: string;97value?: URI | Location;98}99100export enum ChatResponseReferencePartStatusKind {101Complete = 1,102Partial = 2,103Omitted = 3104}105106export enum ChatResponseClearToPreviousToolInvocationReason {107NoReason = 0,108FilteredContentRetry = 1,109CopyrightContentRetry = 2,110}111112export interface IChatContentReference {113reference: URI | Location | IChatContentVariableReference | string;114iconPath?: ThemeIcon | { light: URI; dark?: URI };115options?: {116status?: { description: string; kind: ChatResponseReferencePartStatusKind };117diffMeta?: { added: number; removed: number };118};119kind: 'reference';120}121122export interface IChatChangesSummary {123readonly reference: URI;124readonly sessionId: string;125readonly requestId: string;126readonly kind: 'changesSummary';127}128129export interface IChatCodeCitation {130value: URI;131license: string;132snippet: string;133kind: 'codeCitation';134}135136export interface IChatContentInlineReference {137resolveId?: string;138inlineReference: URI | Location | IWorkspaceSymbol;139name?: string;140kind: 'inlineReference';141}142143export interface IChatMarkdownContent {144content: IMarkdownString;145inlineReferences?: Record<string, IChatContentInlineReference>;146kind: 'markdownContent';147}148149export interface IChatTreeData {150treeData: IChatResponseProgressFileTreeData;151kind: 'treeData';152}153export interface IChatMultiDiffData {154multiDiffData: {155title: string;156resources: Array<{157originalUri?: URI;158modifiedUri?: URI;159goToFileUri?: URI;160added?: number;161removed?: number;162}>;163};164kind: 'multiDiffData';165}166167export interface IChatProgressMessage {168content: IMarkdownString;169kind: 'progressMessage';170}171172export interface IChatTask extends IChatTaskDto {173deferred: DeferredPromise<string | void>;174progress: (IChatWarningMessage | IChatContentReference)[];175onDidAddProgress: Event<IChatWarningMessage | IChatContentReference>;176add(progress: IChatWarningMessage | IChatContentReference): void;177178complete: (result: string | void) => void;179task: () => Promise<string | void>;180isSettled: () => boolean;181}182183export interface IChatUndoStop {184kind: 'undoStop';185id: string;186}187188export interface IChatTaskDto {189content: IMarkdownString;190kind: 'progressTask';191}192193export interface IChatTaskSerialized {194content: IMarkdownString;195progress: (IChatWarningMessage | IChatContentReference)[];196kind: 'progressTaskSerialized';197}198199export interface IChatTaskResult {200content: IMarkdownString | void;201kind: 'progressTaskResult';202}203204export interface IChatWarningMessage {205content: IMarkdownString;206kind: 'warning';207}208209export interface IChatAgentVulnerabilityDetails {210title: string;211description: string;212}213214export interface IChatResponseCodeblockUriPart {215kind: 'codeblockUri';216uri: URI;217isEdit?: boolean;218}219220export interface IChatAgentMarkdownContentWithVulnerability {221content: IMarkdownString;222vulnerabilities: IChatAgentVulnerabilityDetails[];223kind: 'markdownVuln';224}225226export interface IChatCommandButton {227command: Command;228kind: 'command';229}230231export interface IChatMoveMessage {232uri: URI;233range: IRange;234kind: 'move';235}236237export interface IChatTextEdit {238uri: URI;239edits: TextEdit[];240kind: 'textEdit';241done?: boolean;242}243244export interface IChatClearToPreviousToolInvocation {245kind: 'clearToPreviousToolInvocation';246reason: ChatResponseClearToPreviousToolInvocationReason;247}248249export interface IChatNotebookEdit {250uri: URI;251edits: ICellEditOperation[];252kind: 'notebookEdit';253done?: boolean;254}255256export interface IChatConfirmation {257title: string;258message: string | IMarkdownString;259data: any;260buttons?: string[];261isUsed?: boolean;262kind: 'confirmation';263}264265export interface IChatElicitationRequest {266kind: 'elicitation';267title: string | IMarkdownString;268message: string | IMarkdownString;269acceptButtonLabel: string;270rejectButtonLabel: string;271subtitle?: string | IMarkdownString;272source?: ToolDataSource;273state: 'pending' | 'accepted' | 'rejected';274acceptedResult?: Record<string, unknown>;275moreActions?: IAction[];276accept(value: IAction | true): Promise<void>;277reject(): Promise<void>;278onDidRequestHide?: Event<void>;279}280281export interface IChatThinkingPart {282kind: 'thinking';283value?: string | string[];284id?: string;285metadata?: { readonly [key: string]: any };286}287288export interface IChatTerminalToolInvocationData {289kind: 'terminal';290commandLine: {291original: string;292userEdited?: string;293toolEdited?: string;294};295/** Message for model recommending the use of an alternative tool */296alternativeRecommendation?: string;297language: string;298terminalToolSessionId?: string;299autoApproveInfo?: IMarkdownString;300}301302/**303* @deprecated This is the old API shape, we should support this for a while before removing it so304* we don't break existing chats305*/306export interface ILegacyChatTerminalToolInvocationData {307kind: 'terminal';308command: string;309language: string;310}311312export interface IChatToolInputInvocationData {313kind: 'input';314rawInput: any;315}316317export const enum ToolConfirmKind {318Denied,319ConfirmationNotNeeded,320Setting,321LmServicePerTool,322UserAction,323Skipped324}325326export type ConfirmedReason =327| { type: ToolConfirmKind.Denied }328| { type: ToolConfirmKind.ConfirmationNotNeeded }329| { type: ToolConfirmKind.Setting; id: string }330| { type: ToolConfirmKind.LmServicePerTool; scope: 'session' | 'workspace' | 'profile' }331| { type: ToolConfirmKind.UserAction }332| { type: ToolConfirmKind.Skipped };333334export interface IChatToolInvocation {335presentation: IPreparedToolInvocation['presentation'];336toolSpecificData?: IChatTerminalToolInvocationData | ILegacyChatTerminalToolInvocationData | IChatToolInputInvocationData | IChatExtensionsContent | IChatPullRequestContent | IChatTodoListContent;337/** Presence of this property says that confirmation is required */338confirmationMessages?: IToolConfirmationMessages;339confirmed: DeferredPromise<ConfirmedReason>;340/** undefined=don't know yet. */341isConfirmed: ConfirmedReason | undefined;342originMessage: string | IMarkdownString | undefined;343invocationMessage: string | IMarkdownString;344pastTenseMessage: string | IMarkdownString | undefined;345resultDetails: IToolResult['toolResultDetails'];346source: ToolDataSource;347progress: IObservable<{ message?: string | IMarkdownString; progress: number }>;348readonly toolId: string;349readonly toolCallId: string;350351isCompletePromise: Promise<void>;352isComplete: boolean;353complete(result: IToolResult): void;354kind: 'toolInvocation';355}356357export interface IToolResultOutputDetailsSerialized {358output: {359type: 'data';360mimeType: string;361base64Data: string;362};363}364365/**366* This is a IChatToolInvocation that has been serialized, like after window reload, so it is no longer an active tool invocation.367*/368export interface IChatToolInvocationSerialized {369presentation: IPreparedToolInvocation['presentation'];370toolSpecificData?: IChatTerminalToolInvocationData | IChatToolInputInvocationData | IChatExtensionsContent | IChatPullRequestContent | IChatTodoListContent;371invocationMessage: string | IMarkdownString;372originMessage: string | IMarkdownString | undefined;373pastTenseMessage: string | IMarkdownString | undefined;374resultDetails?: Array<URI | Location> | IToolResultInputOutputDetails | IToolResultOutputDetailsSerialized;375/** boolean used by pre-1.104 versions */376isConfirmed: ConfirmedReason | boolean | undefined;377isComplete: boolean;378toolCallId: string;379toolId: string;380source: ToolDataSource;381kind: 'toolInvocationSerialized';382}383384export interface IChatExtensionsContent {385extensions: string[];386kind: 'extensions';387}388389export interface IChatPullRequestContent {390uri: URI;391title: string;392description: string;393author: string;394linkTag: string;395kind: 'pullRequest';396}397398export interface IChatTodoListContent {399kind: 'todoList';400sessionId: string;401todoList: Array<{402id: string;403title: string;404description: string;405status: 'not-started' | 'in-progress' | 'completed';406}>;407}408409export interface IChatPrepareToolInvocationPart {410readonly kind: 'prepareToolInvocation';411readonly toolName: string;412}413414export type IChatProgress =415| IChatMarkdownContent416| IChatAgentMarkdownContentWithVulnerability417| IChatTreeData418| IChatMultiDiffData419| IChatUsedContext420| IChatContentReference421| IChatContentInlineReference422| IChatCodeCitation423| IChatProgressMessage424| IChatTask425| IChatTaskResult426| IChatCommandButton427| IChatWarningMessage428| IChatTextEdit429| IChatNotebookEdit430| IChatMoveMessage431| IChatResponseCodeblockUriPart432| IChatConfirmation433| IChatClearToPreviousToolInvocation434| IChatToolInvocation435| IChatToolInvocationSerialized436| IChatExtensionsContent437| IChatPullRequestContent438| IChatUndoStop439| IChatPrepareToolInvocationPart440| IChatThinkingPart441| IChatTaskSerialized442| IChatElicitationRequest;443444export interface IChatFollowup {445kind: 'reply';446message: string;447agentId: string;448subCommand?: string;449title?: string;450tooltip?: string;451}452453export enum ChatAgentVoteDirection {454Down = 0,455Up = 1456}457458export enum ChatAgentVoteDownReason {459IncorrectCode = 'incorrectCode',460DidNotFollowInstructions = 'didNotFollowInstructions',461IncompleteCode = 'incompleteCode',462MissingContext = 'missingContext',463PoorlyWrittenOrFormatted = 'poorlyWrittenOrFormatted',464RefusedAValidRequest = 'refusedAValidRequest',465OffensiveOrUnsafe = 'offensiveOrUnsafe',466Other = 'other',467WillReportIssue = 'willReportIssue'468}469470export interface IChatVoteAction {471kind: 'vote';472direction: ChatAgentVoteDirection;473reason: ChatAgentVoteDownReason | undefined;474}475476export enum ChatCopyKind {477// Keyboard shortcut or context menu478Action = 1,479Toolbar = 2480}481482export interface IChatCopyAction {483kind: 'copy';484codeBlockIndex: number;485copyKind: ChatCopyKind;486copiedCharacters: number;487totalCharacters: number;488copiedText: string;489totalLines: number;490copiedLines: number;491modelId: string;492languageId?: string;493}494495export interface IChatInsertAction {496kind: 'insert';497codeBlockIndex: number;498totalCharacters: number;499totalLines: number;500languageId?: string;501modelId: string;502newFile?: boolean;503}504505export interface IChatApplyAction {506kind: 'apply';507codeBlockIndex: number;508totalCharacters: number;509totalLines: number;510languageId?: string;511modelId: string;512newFile?: boolean;513codeMapper?: string;514editsProposed: boolean;515}516517518export interface IChatTerminalAction {519kind: 'runInTerminal';520codeBlockIndex: number;521languageId?: string;522}523524export interface IChatCommandAction {525kind: 'command';526commandButton: IChatCommandButton;527}528529export interface IChatFollowupAction {530kind: 'followUp';531followup: IChatFollowup;532}533534export interface IChatBugReportAction {535kind: 'bug';536}537538export interface IChatInlineChatCodeAction {539kind: 'inlineChat';540action: 'accepted' | 'discarded';541}542543544export interface IChatEditingSessionAction {545kind: 'chatEditingSessionAction';546uri: URI;547hasRemainingEdits: boolean;548outcome: 'accepted' | 'rejected' | 'userModified';549}550551export interface IChatEditingHunkAction {552kind: 'chatEditingHunkAction';553uri: URI;554lineCount: number;555linesAdded: number;556linesRemoved: number;557outcome: 'accepted' | 'rejected';558hasRemainingEdits: boolean;559modeId?: string;560modelId?: string;561languageId?: string;562}563564export type ChatUserAction = IChatVoteAction | IChatCopyAction | IChatInsertAction | IChatApplyAction | IChatTerminalAction | IChatCommandAction | IChatFollowupAction | IChatBugReportAction | IChatInlineChatCodeAction | IChatEditingSessionAction | IChatEditingHunkAction;565566export interface IChatUserActionEvent {567action: ChatUserAction;568agentId: string | undefined;569command: string | undefined;570sessionId: string;571requestId: string;572result: IChatAgentResult | undefined;573modelId?: string | undefined;574modeId?: string | undefined;575}576577export interface IChatDynamicRequest {578/**579* The message that will be displayed in the UI580*/581message: string;582583/**584* Any extra metadata/context that will go to the provider.585*/586metadata?: any;587}588589export interface IChatCompleteResponse {590message: string | ReadonlyArray<IChatProgress>;591result?: IChatAgentResult;592followups?: IChatFollowup[];593}594595export interface IChatDetail {596sessionId: string;597title: string;598lastMessageDate: number;599isActive: boolean;600}601602export interface IChatProviderInfo {603id: string;604}605606export interface IChatTransferredSessionData {607sessionId: string;608inputValue: string;609location: ChatAgentLocation;610mode: ChatModeKind;611}612613export interface IChatSendRequestResponseState {614responseCreatedPromise: Promise<IChatResponseModel>;615responseCompletePromise: Promise<void>;616}617618export interface IChatSendRequestData extends IChatSendRequestResponseState {619agent: IChatAgentData;620slashCommand?: IChatAgentCommand;621}622623export interface IChatEditorLocationData {624type: ChatAgentLocation.Editor;625document: URI;626selection: ISelection;627wholeRange: IRange;628}629630export interface IChatNotebookLocationData {631type: ChatAgentLocation.Notebook;632sessionInputUri: URI;633}634635export interface IChatTerminalLocationData {636type: ChatAgentLocation.Terminal;637// TBD638}639640export type IChatLocationData = IChatEditorLocationData | IChatNotebookLocationData | IChatTerminalLocationData;641642export interface IChatSendRequestOptions {643modeInfo?: IChatRequestModeInfo;644userSelectedModelId?: string;645userSelectedTools?: IObservable<UserSelectedTools>;646location?: ChatAgentLocation;647locationData?: IChatLocationData;648parserContext?: IChatParserContext;649attempt?: number;650noCommandDetection?: boolean;651acceptedConfirmationData?: any[];652rejectedConfirmationData?: any[];653attachedContext?: IChatRequestVariableEntry[];654655/** The target agent ID can be specified with this property instead of using @ in 'message' */656agentId?: string;657/** agentId, but will not add a @ name to the request */658agentIdSilent?: string;659slashCommand?: string;660661/**662* The label of the confirmation action that was selected.663*/664confirmation?: string;665}666667export const IChatService = createDecorator<IChatService>('IChatService');668669export interface IChatService {670_serviceBrand: undefined;671transferredSessionData: IChatTransferredSessionData | undefined;672673onDidSubmitRequest: Event<{ chatSessionId: string }>;674675isEnabled(location: ChatAgentLocation): boolean;676hasSessions(): boolean;677startSession(location: ChatAgentLocation, token: CancellationToken, isGlobalEditingSession?: boolean): ChatModel;678getSession(sessionId: string): IChatModel | undefined;679getOrRestoreSession(sessionId: string): Promise<IChatModel | undefined>;680getPersistedSessionTitle(sessionId: string): string | undefined;681isPersistedSessionEmpty(sessionId: string): boolean;682loadSessionFromContent(data: IExportableChatData | ISerializableChatData | URI): IChatModel | undefined;683loadSessionForResource(resource: URI, location: ChatAgentLocation, token: CancellationToken): Promise<IChatModel | undefined>;684685/**686* Returns whether the request was accepted.687*/688sendRequest(sessionId: string, message: string, options?: IChatSendRequestOptions): Promise<IChatSendRequestData | undefined>;689690resendRequest(request: IChatRequestModel, options?: IChatSendRequestOptions): Promise<void>;691adoptRequest(sessionId: string, request: IChatRequestModel): Promise<void>;692removeRequest(sessionid: string, requestId: string): Promise<void>;693cancelCurrentRequestForSession(sessionId: string): void;694clearSession(sessionId: string): Promise<void>;695addCompleteRequest(sessionId: string, message: IParsedChatRequest | string, variableData: IChatRequestVariableData | undefined, attempt: number | undefined, response: IChatCompleteResponse): void;696getHistory(): Promise<IChatDetail[]>;697setChatSessionTitle(sessionId: string, title: string): void;698clearAllHistoryEntries(): Promise<void>;699removeHistoryEntry(sessionId: string): Promise<void>;700getChatStorageFolder(): URI;701logChatIndex(): void;702703onDidPerformUserAction: Event<IChatUserActionEvent>;704notifyUserAction(event: IChatUserActionEvent): void;705onDidDisposeSession: Event<{ sessionId: string; reason: 'cleared' }>;706707transferChatSession(transferredSessionData: IChatTransferredSessionData, toWorkspace: URI): void;708709activateDefaultAgent(location: ChatAgentLocation): Promise<void>;710711readonly edits2Enabled: boolean;712713readonly requestInProgressObs: IObservable<boolean>;714}715716export const KEYWORD_ACTIVIATION_SETTING_ID = 'accessibility.voice.keywordActivation';717718719