mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-24 12:19:20 +00:00
Add editedFileEvents (#246996)
* Start plumbing working set events * more * More fixes * Update tests
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import 'mocha';
|
||||
import { ChatContext, ChatRequest, ChatResult, Disposable, Event, EventEmitter, chat, commands, lm } from 'vscode';
|
||||
import { ChatContext, ChatRequest, ChatRequestTurn, ChatRequestTurn2, ChatResult, Disposable, Event, EventEmitter, chat, commands, lm } from 'vscode';
|
||||
import { DeferredPromise, asPromise, assertNoRpc, closeAllEditors, delay, disposeAll } from '../utils';
|
||||
|
||||
suite('chat', () => {
|
||||
@@ -71,6 +71,7 @@ suite('chat', () => {
|
||||
assert.strictEqual(request.context.history.length, 2);
|
||||
assert.strictEqual(request.context.history[0].participant, 'api-test.participant');
|
||||
assert.strictEqual(request.context.history[0].command, 'hello');
|
||||
assert.ok(request.context.history[0] instanceof ChatRequestTurn && request.context.history[0] instanceof ChatRequestTurn2);
|
||||
deferred.complete();
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -1800,11 +1800,13 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
ChatResponseExtensionsPart: extHostTypes.ChatResponseExtensionsPart,
|
||||
ChatResponseReferencePartStatusKind: extHostTypes.ChatResponseReferencePartStatusKind,
|
||||
ChatRequestTurn: extHostTypes.ChatRequestTurn,
|
||||
ChatRequestTurn2: extHostTypes.ChatRequestTurn,
|
||||
ChatResponseTurn: extHostTypes.ChatResponseTurn,
|
||||
ChatLocation: extHostTypes.ChatLocation,
|
||||
ChatRequestEditorData: extHostTypes.ChatRequestEditorData,
|
||||
ChatRequestNotebookData: extHostTypes.ChatRequestNotebookData,
|
||||
ChatReferenceBinaryData: extHostTypes.ChatReferenceBinaryData,
|
||||
ChatRequestEditedFileEventKind: extHostTypes.ChatRequestEditedFileEventKind,
|
||||
LanguageModelChatMessageRole: extHostTypes.LanguageModelChatMessageRole,
|
||||
LanguageModelChatMessage: extHostTypes.LanguageModelChatMessage,
|
||||
LanguageModelChatMessage2: extHostTypes.LanguageModelChatMessage2,
|
||||
|
||||
@@ -410,8 +410,7 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS
|
||||
const { request, location, history } = await this._createRequest(requestDto, context, detector.extension);
|
||||
|
||||
const model = await this.getModelForRequest(request, detector.extension);
|
||||
const includeInteractionId = isProposedApiEnabled(detector.extension, 'chatParticipantPrivate');
|
||||
const extRequest = typeConvert.ChatAgentRequest.to(includeInteractionId ? request : { ...request, requestId: '' }, location, model, this.getDiagnosticsWhenEnabled(detector.extension), this.getToolsForRequest(detector.extension, request));
|
||||
const extRequest = typeConvert.ChatAgentRequest.to(request, location, model, this.getDiagnosticsWhenEnabled(detector.extension), this.getToolsForRequest(detector.extension, request), detector.extension);
|
||||
|
||||
return detector.provider.provideParticipantDetection(
|
||||
extRequest,
|
||||
@@ -495,13 +494,13 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS
|
||||
stream = new ChatAgentResponseStream(agent.extension, request, this._proxy, this._commands.converter, sessionDisposables);
|
||||
|
||||
const model = await this.getModelForRequest(request, agent.extension);
|
||||
const includeInteractionId = isProposedApiEnabled(agent.extension, 'chatParticipantPrivate');
|
||||
const extRequest = typeConvert.ChatAgentRequest.to(
|
||||
includeInteractionId ? request : { ...request, requestId: '' },
|
||||
request,
|
||||
location,
|
||||
model,
|
||||
this.getDiagnosticsWhenEnabled(agent.extension),
|
||||
this.getToolsForRequest(agent.extension, request)
|
||||
this.getToolsForRequest(agent.extension, request),
|
||||
agent.extension
|
||||
);
|
||||
inFlightRequest = { requestId: requestDto.requestId, extRequest };
|
||||
this._inFlightRequests.add(inFlightRequest);
|
||||
@@ -585,7 +584,8 @@ export class ExtHostChatAgents2 extends Disposable implements ExtHostChatAgentsS
|
||||
const toolReferences = h.request.variables.variables
|
||||
.filter(v => v.kind === 'tool')
|
||||
.map(typeConvert.ChatLanguageModelToolReference.to);
|
||||
const turn = new extHostTypes.ChatRequestTurn(h.request.message, h.request.command, varsWithoutTools, h.request.agentId, toolReferences);
|
||||
const editedFileEvents = isProposedApiEnabled(extension, 'chatParticipantPrivate') ? h.request.editedFileEvents : undefined;
|
||||
const turn = new extHostTypes.ChatRequestTurn(h.request.message, h.request.command, varsWithoutTools, h.request.agentId, toolReferences, editedFileEvents);
|
||||
res.push(turn);
|
||||
|
||||
// RESPONSE turn
|
||||
|
||||
@@ -34,7 +34,7 @@ import * as languageSelector from '../../../editor/common/languageSelector.js';
|
||||
import * as languages from '../../../editor/common/languages.js';
|
||||
import { EndOfLineSequence, TrackedRangeStickiness } from '../../../editor/common/model.js';
|
||||
import { ITextEditorOptions } from '../../../platform/editor/common/editor.js';
|
||||
import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
|
||||
import { IExtensionDescription, IRelaxedExtensionDescription } from '../../../platform/extensions/common/extensions.js';
|
||||
import { IMarkerData, IRelatedInformation, MarkerSeverity, MarkerTag } from '../../../platform/markers/common/markers.js';
|
||||
import { ProgressLocation as MainProgressLocation } from '../../../platform/progress/common/progress.js';
|
||||
import { DEFAULT_EDITOR_ASSOCIATION, SaveReason } from '../../common/editor.js';
|
||||
@@ -55,7 +55,7 @@ import { TestId } from '../../contrib/testing/common/testId.js';
|
||||
import { CoverageDetails, DetailType, ICoverageCount, IFileCoverage, ISerializedTestResults, ITestErrorMessage, ITestItem, ITestRunProfileReference, ITestTag, TestMessageType, TestResultItem, TestRunProfileBitset, denamespaceTestTag, namespaceTestTag } from '../../contrib/testing/common/testTypes.js';
|
||||
import { EditorGroupColumn } from '../../services/editor/common/editorGroupColumn.js';
|
||||
import { ACTIVE_GROUP, SIDE_GROUP } from '../../services/editor/common/editorService.js';
|
||||
import { checkProposedApiEnabled } from '../../services/extensions/common/extensions.js';
|
||||
import { checkProposedApiEnabled, isProposedApiEnabled } from '../../services/extensions/common/extensions.js';
|
||||
import { Dto } from '../../services/extensions/common/proxyIdentifier.js';
|
||||
import * as extHostProtocol from './extHost.protocol.js';
|
||||
import { CommandsConverter } from './extHostCommands.js';
|
||||
@@ -2897,10 +2897,11 @@ export namespace ChatResponsePart {
|
||||
}
|
||||
|
||||
export namespace ChatAgentRequest {
|
||||
export function to(request: IChatAgentRequest, location2: vscode.ChatRequestEditorData | vscode.ChatRequestNotebookData | undefined, model: vscode.LanguageModelChat, diagnostics: readonly [vscode.Uri, readonly vscode.Diagnostic[]][], tools: vscode.LanguageModelToolInformation[] | undefined): vscode.ChatRequest {
|
||||
export function to(request: IChatAgentRequest, location2: vscode.ChatRequestEditorData | vscode.ChatRequestNotebookData | undefined, model: vscode.LanguageModelChat, diagnostics: readonly [vscode.Uri, readonly vscode.Diagnostic[]][], tools: vscode.LanguageModelToolInformation[] | undefined, extension: IRelaxedExtensionDescription): vscode.ChatRequest {
|
||||
const toolReferences = request.variables.variables.filter(v => v.kind === 'tool');
|
||||
const variableReferences = request.variables.variables.filter(v => v.kind !== 'tool');
|
||||
const requestWithoutId = {
|
||||
const requestWithAllProps: vscode.ChatRequest = {
|
||||
id: request.requestId,
|
||||
prompt: request.message,
|
||||
command: request.command,
|
||||
attempt: request.attempt ?? 0,
|
||||
@@ -2914,16 +2915,28 @@ export namespace ChatAgentRequest {
|
||||
location2,
|
||||
toolInvocationToken: Object.freeze({ sessionId: request.sessionId }) as never,
|
||||
tools,
|
||||
model
|
||||
model,
|
||||
editedFileEvents: request.editedFileEvents,
|
||||
};
|
||||
if (request.requestId) {
|
||||
return {
|
||||
...requestWithoutId,
|
||||
id: request.requestId
|
||||
};
|
||||
|
||||
if (!isProposedApiEnabled(extension, 'chatParticipantPrivate')) {
|
||||
delete (requestWithAllProps as any).id;
|
||||
delete (requestWithAllProps as any).attempt;
|
||||
delete (requestWithAllProps as any).enableCommandDetection;
|
||||
delete (requestWithAllProps as any).isParticipantDetected;
|
||||
delete (requestWithAllProps as any).location;
|
||||
delete (requestWithAllProps as any).location2;
|
||||
delete (requestWithAllProps as any).editedFileEvents;
|
||||
}
|
||||
// This cast is done to allow sending the stabl version of ChatRequest which does not have an id property
|
||||
return requestWithoutId as unknown as vscode.ChatRequest;
|
||||
|
||||
if (!isProposedApiEnabled(extension, 'chatParticipantAdditions')) {
|
||||
delete requestWithAllProps.acceptedConfirmationData;
|
||||
delete requestWithAllProps.rejectedConfirmationData;
|
||||
delete (requestWithAllProps as any).tools;
|
||||
}
|
||||
|
||||
|
||||
return requestWithAllProps;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4525,6 +4525,12 @@ export enum ChatEditingSessionActionOutcome {
|
||||
Saved = 3
|
||||
}
|
||||
|
||||
export enum ChatRequestEditedFileEventKind {
|
||||
Keep = 1,
|
||||
Undo = 2,
|
||||
UserModification = 3,
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Interactive Editor
|
||||
@@ -4718,13 +4724,14 @@ export class ChatResponseNotebookEditPart implements vscode.ChatResponseNotebook
|
||||
}
|
||||
}
|
||||
|
||||
export class ChatRequestTurn implements vscode.ChatRequestTurn {
|
||||
export class ChatRequestTurn implements vscode.ChatRequestTurn2 {
|
||||
constructor(
|
||||
readonly prompt: string,
|
||||
readonly command: string | undefined,
|
||||
readonly references: vscode.ChatPromptReference[],
|
||||
readonly participant: string,
|
||||
readonly toolReferences: vscode.ChatLanguageModelToolReference[]
|
||||
readonly toolReferences: vscode.ChatLanguageModelToolReference[],
|
||||
readonly editedFileEvents?: vscode.ChatRequestEditedFileEvent[]
|
||||
) { }
|
||||
}
|
||||
|
||||
|
||||
@@ -236,7 +236,6 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie
|
||||
const e_sum = this._edit;
|
||||
const e_ai = edit;
|
||||
this._edit = e_sum.compose(e_ai);
|
||||
|
||||
} else {
|
||||
|
||||
// e_ai
|
||||
@@ -269,6 +268,7 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie
|
||||
}
|
||||
|
||||
this._allEditsAreFromUs = false;
|
||||
this._userEditScheduler.schedule();
|
||||
this._updateDiffInfoSeq();
|
||||
|
||||
const didResetToOriginalContent = this.modifiedModel.getValue() === this.initialContent;
|
||||
@@ -348,6 +348,7 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie
|
||||
await this._updateDiffInfoSeq();
|
||||
if (this._diffInfo.get().identical) {
|
||||
this._stateObs.set(ModifiedFileEntryState.Accepted, undefined);
|
||||
this._notifyAction('accepted');
|
||||
}
|
||||
this._accessibilitySignalService.playSignal(AccessibilitySignal.editsKept, { allowManyInParallel: true });
|
||||
return true;
|
||||
@@ -366,6 +367,7 @@ export class ChatEditingModifiedDocumentEntry extends AbstractChatEditingModifie
|
||||
await this._updateDiffInfoSeq();
|
||||
if (this._diffInfo.get().identical) {
|
||||
this._stateObs.set(ModifiedFileEntryState.Rejected, undefined);
|
||||
this._notifyAction('rejected');
|
||||
}
|
||||
this._accessibilitySignalService.playSignal(AccessibilitySignal.editsUndone, { allowManyInParallel: true });
|
||||
return true;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { RunOnceScheduler } from '../../../../../base/common/async.js';
|
||||
import { Emitter } from '../../../../../base/common/event.js';
|
||||
import { Disposable, DisposableMap, MutableDisposable } from '../../../../../base/common/lifecycle.js';
|
||||
import { Schemas } from '../../../../../base/common/network.js';
|
||||
@@ -81,6 +82,8 @@ export abstract class AbstractChatEditingModifiedFileEntry extends Disposable im
|
||||
|
||||
readonly abstract originalURI: URI;
|
||||
|
||||
protected readonly _userEditScheduler = this._register(new RunOnceScheduler(() => this._notifyAction('userModified'), 1000));
|
||||
|
||||
constructor(
|
||||
readonly modifiedURI: URI,
|
||||
protected _telemetryInfo: IModifiedEntryTelemetryInfo,
|
||||
@@ -189,7 +192,7 @@ export abstract class AbstractChatEditingModifiedFileEntry extends Disposable im
|
||||
|
||||
protected abstract _doReject(tx: ITransaction | undefined): Promise<void>;
|
||||
|
||||
private _notifyAction(outcome: 'accepted' | 'rejected') {
|
||||
protected _notifyAction(outcome: 'accepted' | 'rejected' | 'userModified') {
|
||||
this._chatService.notifyUserAction({
|
||||
action: { kind: 'chatEditingSessionAction', uri: this.modifiedURI, hasRemainingEdits: false, outcome },
|
||||
agentId: this._telemetryInfo.agentId,
|
||||
|
||||
@@ -24,7 +24,7 @@ import { IProductService } from '../../../../platform/product/common/productServ
|
||||
import { asJson, IRequestService } from '../../../../platform/request/common/request.js';
|
||||
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
|
||||
import { ChatContextKeys } from './chatContextKeys.js';
|
||||
import { IChatProgressHistoryResponseContent, IChatRequestVariableData, ISerializableChatAgentData } from './chatModel.js';
|
||||
import { IChatAgentEditedFileEvent, IChatProgressHistoryResponseContent, IChatRequestVariableData, ISerializableChatAgentData } from './chatModel.js';
|
||||
import { IRawChatCommandContribution } from './chatParticipantContribTypes.js';
|
||||
import { IChatFollowup, IChatLocationData, IChatProgress, IChatResponseErrorDetails, IChatTaskDto } from './chatService.js';
|
||||
import { ChatAgentLocation, ChatMode } from './constants.js';
|
||||
@@ -138,6 +138,7 @@ export interface IChatAgentRequest {
|
||||
rejectedConfirmationData?: any[];
|
||||
userSelectedModelId?: string;
|
||||
userSelectedTools?: string[];
|
||||
editedFileEvents?: IChatAgentEditedFileEvent[];
|
||||
}
|
||||
|
||||
export interface IChatQuestion {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Codicon } from '../../../../base/common/codicons.js';
|
||||
import { Emitter, Event } from '../../../../base/common/event.js';
|
||||
import { IMarkdownString, MarkdownString, isMarkdownString } from '../../../../base/common/htmlContent.js';
|
||||
import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js';
|
||||
import { ResourceMap } from '../../../../base/common/map.js';
|
||||
import { revive } from '../../../../base/common/marshalling.js';
|
||||
import { Schemas } from '../../../../base/common/network.js';
|
||||
import { equals } from '../../../../base/common/objects.js';
|
||||
@@ -27,7 +28,7 @@ import { CellUri, ICellEditOperation } from '../../notebook/common/notebookCommo
|
||||
import { IChatAgentCommand, IChatAgentData, IChatAgentResult, IChatAgentService, reviveSerializedAgent } from './chatAgents.js';
|
||||
import { IChatEditingService, IChatEditingSession } from './chatEditingService.js';
|
||||
import { ChatRequestTextPart, IParsedChatRequest, reviveParsedChatRequest } from './chatParserTypes.js';
|
||||
import { ChatAgentVoteDirection, ChatAgentVoteDownReason, IChatAgentMarkdownContentWithVulnerability, IChatCodeCitation, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatExtensionsContent, IChatFollowup, IChatLocationData, IChatMarkdownContent, IChatNotebookEdit, IChatProgress, IChatProgressMessage, IChatResponseCodeblockUriPart, IChatResponseProgressFileTreeData, IChatTask, IChatTextEdit, IChatToolInvocation, IChatToolInvocationSerialized, IChatTreeData, IChatUndoStop, IChatUsedContext, IChatWarningMessage, isIUsedContext } from './chatService.js';
|
||||
import { ChatAgentVoteDirection, ChatAgentVoteDownReason, IChatAgentMarkdownContentWithVulnerability, IChatCodeCitation, IChatCommandButton, IChatConfirmation, IChatContentInlineReference, IChatContentReference, IChatEditingSessionAction, IChatExtensionsContent, IChatFollowup, IChatLocationData, IChatMarkdownContent, IChatNotebookEdit, IChatProgress, IChatProgressMessage, IChatResponseCodeblockUriPart, IChatResponseProgressFileTreeData, IChatTask, IChatTextEdit, IChatToolInvocation, IChatToolInvocationSerialized, IChatTreeData, IChatUndoStop, IChatUsedContext, IChatWarningMessage, isIUsedContext } from './chatService.js';
|
||||
import { IChatRequestVariableValue } from './chatVariables.js';
|
||||
import { ChatAgentLocation, ChatMode } from './constants.js';
|
||||
|
||||
@@ -248,6 +249,7 @@ export interface IChatRequestModel {
|
||||
readonly attachedContext?: IChatRequestVariableEntry[];
|
||||
readonly isCompleteAddedRequest: boolean;
|
||||
readonly response?: IChatResponseModel;
|
||||
readonly editedFileEvents?: IChatAgentEditedFileEvent[];
|
||||
shouldBeRemovedOnSend: IChatRequestDisablement | undefined;
|
||||
}
|
||||
|
||||
@@ -389,6 +391,7 @@ export interface IChatRequestModelParameters {
|
||||
isCompleteAddedRequest?: boolean;
|
||||
modelId?: string;
|
||||
restoredId?: string;
|
||||
editedFileEvents?: IChatAgentEditedFileEvent[];
|
||||
}
|
||||
|
||||
export class ChatRequestModel implements IChatRequestModel {
|
||||
@@ -406,6 +409,7 @@ export class ChatRequestModel implements IChatRequestModel {
|
||||
private readonly _confirmation?: string;
|
||||
private readonly _locationData?: IChatLocationData;
|
||||
private readonly _attachedContext?: IChatRequestVariableEntry[];
|
||||
private readonly _editedFileEvents?: IChatAgentEditedFileEvent[];
|
||||
|
||||
public get session(): ChatModel {
|
||||
return this._session;
|
||||
@@ -443,6 +447,10 @@ export class ChatRequestModel implements IChatRequestModel {
|
||||
return this._attachedContext;
|
||||
}
|
||||
|
||||
public get editedFileEvents(): IChatAgentEditedFileEvent[] | undefined {
|
||||
return this._editedFileEvents;
|
||||
}
|
||||
|
||||
constructor(params: IChatRequestModelParameters) {
|
||||
this._session = params.session;
|
||||
this.message = params.message;
|
||||
@@ -455,6 +463,7 @@ export class ChatRequestModel implements IChatRequestModel {
|
||||
this.isCompleteAddedRequest = params.isCompleteAddedRequest ?? false;
|
||||
this.modelId = params.modelId;
|
||||
this.id = params.restoredId ?? 'request_' + generateUuid();
|
||||
this._editedFileEvents = params.editedFileEvents;
|
||||
}
|
||||
|
||||
adoptTo(session: ChatModel) {
|
||||
@@ -1082,6 +1091,7 @@ export interface ISerializableChatRequestData {
|
||||
codeCitations?: ReadonlyArray<IChatCodeCitation>;
|
||||
timestamp?: number;
|
||||
confirmation?: string;
|
||||
editedFileEvents?: IChatAgentEditedFileEvent[];
|
||||
}
|
||||
|
||||
export interface IExportableChatData {
|
||||
@@ -1437,7 +1447,37 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||
this.chatEditingService.startOrContinueGlobalEditingSession(this) :
|
||||
this.chatEditingService.createEditingSession(this);
|
||||
this._editingSession = new ObservablePromise(editingSessionPromise);
|
||||
this._editingSession.promise.then(editingSession => this._store.isDisposed ? editingSession.dispose() : this._register(editingSession));
|
||||
this._editingSession.promise.then(editingSession => {
|
||||
this._store.isDisposed ? editingSession.dispose() : this._register(editingSession);
|
||||
|
||||
// const currentStates = new ResourceMap<ModifiedFileEntryState>();
|
||||
// this._register(autorun(r => {
|
||||
// editingSession.entries.read(r).forEach(entry => {
|
||||
// const state = entry.state.read(r);
|
||||
// if (state !== currentStates.get(entry.modifiedURI)) {
|
||||
// currentStates.set(entry.modifiedURI, state);
|
||||
// if (state === ModifiedFileEntryState.Rejected) {
|
||||
// this.currentWorkingSetEntries.push({
|
||||
// uri: entry.modifiedURI,
|
||||
// state: ChatAgentWorkingSetEntryState.Rejected
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }));
|
||||
});
|
||||
}
|
||||
|
||||
private currentEditedFileEvents = new ResourceMap<IChatAgentEditedFileEvent>();
|
||||
notifyEditingAction(action: IChatEditingSessionAction): void {
|
||||
const state = action.outcome === 'accepted' ? ChatRequestEditedFileEventKind.Keep :
|
||||
action.outcome === 'rejected' ? ChatRequestEditedFileEventKind.Undo :
|
||||
action.outcome === 'userModified' ? ChatRequestEditedFileEventKind.UserModification : null;
|
||||
if (state === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentEditedFileEvents.set(action.uri, { eventKind: state, uri: action.uri });
|
||||
}
|
||||
|
||||
private _deserialize(obj: IExportableChatData): ChatRequestModel[] {
|
||||
@@ -1463,6 +1503,7 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||
timestamp: raw.timestamp ?? -1,
|
||||
restoredId: raw.requestId,
|
||||
confirmation: raw.confirmation,
|
||||
editedFileEvents: raw.editedFileEvents,
|
||||
});
|
||||
request.shouldBeRemovedOnSend = raw.isHidden ? { requestId: raw.requestId } : raw.shouldBeRemovedOnSend;
|
||||
if (raw.response || raw.result || (raw as any).responseErrorDetails) {
|
||||
@@ -1610,6 +1651,8 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||
}
|
||||
|
||||
addRequest(message: IParsedChatRequest, variableData: IChatRequestVariableData, attempt: number, chatAgent?: IChatAgentData, slashCommand?: IChatAgentCommand, confirmation?: string, locationData?: IChatLocationData, attachments?: IChatRequestVariableEntry[], isCompleteAddedRequest?: boolean, modelId?: string): ChatRequestModel {
|
||||
const editedFileEvents = [...this.currentEditedFileEvents.values()];
|
||||
this.currentEditedFileEvents.clear();
|
||||
const request = new ChatRequestModel({
|
||||
session: this,
|
||||
message,
|
||||
@@ -1620,7 +1663,8 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||
locationData,
|
||||
attachedContext: attachments,
|
||||
isCompleteAddedRequest,
|
||||
modelId
|
||||
modelId,
|
||||
editedFileEvents: editedFileEvents.length ? editedFileEvents : undefined,
|
||||
});
|
||||
request.response = new ChatResponseModel({
|
||||
responseContent: [],
|
||||
@@ -1804,6 +1848,7 @@ export class ChatModel extends Disposable implements IChatModel {
|
||||
codeCitations: r.response?.codeCitations,
|
||||
timestamp: r.timestamp,
|
||||
confirmation: r.confirmation,
|
||||
editedFileEvents: r.editedFileEvents,
|
||||
};
|
||||
}),
|
||||
};
|
||||
@@ -1882,3 +1927,14 @@ export function getCodeCitationsMessage(citations: ReadonlyArray<IChatCodeCitati
|
||||
localize('codeCitations', "Similar code found with {0} license types", licenseTypes.size);
|
||||
return label;
|
||||
}
|
||||
|
||||
export enum ChatRequestEditedFileEventKind {
|
||||
Keep = 1,
|
||||
Undo = 2,
|
||||
UserModification = 3,
|
||||
}
|
||||
|
||||
export interface IChatAgentEditedFileEvent {
|
||||
readonly uri: URI;
|
||||
readonly eventKind: ChatRequestEditedFileEventKind;
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ export interface IChatEditingSessionAction {
|
||||
kind: 'chatEditingSessionAction';
|
||||
uri: URI;
|
||||
hasRemainingEdits: boolean;
|
||||
outcome: 'accepted' | 'rejected' | 'saved';
|
||||
outcome: 'accepted' | 'rejected' | 'userModified';
|
||||
}
|
||||
|
||||
export type ChatUserAction = IChatVoteAction | IChatCopyAction | IChatInsertAction | IChatApplyAction | IChatTerminalAction | IChatCommandAction | IChatFollowupAction | IChatBugReportAction | IChatInlineChatCodeAction | IChatEditingSessionAction;
|
||||
|
||||
@@ -288,6 +288,12 @@ export class ChatService extends Disposable implements IChatService {
|
||||
notifyUserAction(action: IChatUserActionEvent): void {
|
||||
this._chatServiceTelemetry.notifyUserAction(action);
|
||||
this._onDidPerformUserAction.fire(action);
|
||||
if (action.action.kind === 'chatEditingSessionAction') {
|
||||
const model = this._sessionModels.get(action.sessionId);
|
||||
if (model) {
|
||||
model.notifyEditingAction(action.action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async setChatSessionTitle(sessionId: string, title: string): Promise<void> {
|
||||
@@ -761,7 +767,8 @@ export class ChatService extends Disposable implements IChatService {
|
||||
acceptedConfirmationData: options?.acceptedConfirmationData,
|
||||
rejectedConfirmationData: options?.rejectedConfirmationData,
|
||||
userSelectedModelId: options?.userSelectedModelId,
|
||||
userSelectedTools: options?.userSelectedTools
|
||||
userSelectedTools: options?.userSelectedTools,
|
||||
editedFileEvents: request.editedFileEvents
|
||||
} satisfies IChatAgentRequest;
|
||||
};
|
||||
|
||||
@@ -998,7 +1005,8 @@ export class ChatService extends Disposable implements IChatService {
|
||||
message: promptTextResult.message,
|
||||
command: request.response.slashCommand?.name,
|
||||
variables: updateRanges(request.variableData, promptTextResult.diff), // TODO bit of a hack
|
||||
location: ChatAgentLocation.Panel
|
||||
location: ChatAgentLocation.Panel,
|
||||
editedFileEvents: request.editedFileEvents,
|
||||
};
|
||||
history.push({ request: historyRequest, response: toChatHistoryContent(request.response.response.value), result: request.response.result ?? {} });
|
||||
}
|
||||
|
||||
@@ -101,7 +101,8 @@
|
||||
contentReferences: [ ],
|
||||
codeCitations: [ ],
|
||||
timestamp: undefined,
|
||||
confirmation: undefined
|
||||
confirmation: undefined,
|
||||
editedFileEvents: undefined
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -85,7 +85,8 @@
|
||||
contentReferences: [ ],
|
||||
codeCitations: [ ],
|
||||
timestamp: undefined,
|
||||
confirmation: undefined
|
||||
confirmation: undefined,
|
||||
editedFileEvents: undefined
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -108,7 +108,8 @@
|
||||
contentReferences: [ ],
|
||||
codeCitations: [ ],
|
||||
timestamp: undefined,
|
||||
confirmation: undefined
|
||||
confirmation: undefined,
|
||||
editedFileEvents: undefined
|
||||
},
|
||||
{
|
||||
requestId: undefined,
|
||||
@@ -162,7 +163,8 @@
|
||||
contentReferences: [ ],
|
||||
codeCitations: [ ],
|
||||
timestamp: undefined,
|
||||
confirmation: undefined
|
||||
confirmation: undefined,
|
||||
editedFileEvents: undefined
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -85,7 +85,8 @@
|
||||
contentReferences: [ ],
|
||||
codeCitations: [ ],
|
||||
timestamp: undefined,
|
||||
confirmation: undefined
|
||||
confirmation: undefined,
|
||||
editedFileEvents: undefined
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -77,6 +77,67 @@ declare module 'vscode' {
|
||||
* or terminal. Will be `undefined` for the chat panel.
|
||||
*/
|
||||
readonly location2: ChatRequestEditorData | ChatRequestNotebookData | undefined;
|
||||
|
||||
/**
|
||||
* Events for edited files in this session collected since the last request.
|
||||
*/
|
||||
readonly editedFileEvents?: ChatRequestEditedFileEvent[];
|
||||
}
|
||||
|
||||
export enum ChatRequestEditedFileEventKind {
|
||||
Keep = 1,
|
||||
Undo = 2,
|
||||
UserModification = 3,
|
||||
}
|
||||
|
||||
export interface ChatRequestEditedFileEvent {
|
||||
readonly uri: Uri;
|
||||
readonly eventKind: ChatRequestEditedFileEventKind;
|
||||
}
|
||||
|
||||
/**
|
||||
* ChatRequestTurn + private additions. Note- at runtime this is the SAME as ChatRequestTurn and instanceof is safe.
|
||||
*/
|
||||
export class ChatRequestTurn2 {
|
||||
/**
|
||||
* The prompt as entered by the user.
|
||||
*
|
||||
* Information about references used in this request is stored in {@link ChatRequestTurn.references}.
|
||||
*
|
||||
* *Note* that the {@link ChatParticipant.name name} of the participant and the {@link ChatCommand.name command}
|
||||
* are not part of the prompt.
|
||||
*/
|
||||
readonly prompt: string;
|
||||
|
||||
/**
|
||||
* The id of the chat participant to which this request was directed.
|
||||
*/
|
||||
readonly participant: string;
|
||||
|
||||
/**
|
||||
* The name of the {@link ChatCommand command} that was selected for this request.
|
||||
*/
|
||||
readonly command?: string;
|
||||
|
||||
/**
|
||||
* The references that were used in this message.
|
||||
*/
|
||||
readonly references: ChatPromptReference[];
|
||||
|
||||
/**
|
||||
* The list of tools were attached to this request.
|
||||
*/
|
||||
readonly toolReferences: readonly ChatLanguageModelToolReference[];
|
||||
|
||||
/**
|
||||
* Events for edited files in this session collected between the previous request and this one.
|
||||
*/
|
||||
readonly editedFileEvents?: ChatRequestEditedFileEvent[];
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
private constructor(prompt: string, command: string | undefined, references: ChatPromptReference[], participant: string, toolReferences: ChatLanguageModelToolReference[], editedFileEvents: ChatRequestEditedFileEvent[] | undefined);
|
||||
}
|
||||
|
||||
export interface ChatParticipant {
|
||||
|
||||
Reference in New Issue
Block a user