diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index bff7db27ef0..6ea15c8f58c 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -727,14 +727,18 @@ export class ChatModel extends Disposable implements IChatModel { } get requestInProgress(): boolean { - const lastRequest = this._requests[this._requests.length - 1]; - return !!lastRequest && !!lastRequest.response && !lastRequest.response.isComplete; + const lastRequest = this.lastRequest; + return !!lastRequest?.response && !lastRequest.response.isComplete; } get hasRequests(): boolean { return this._requests.length > 0; } + get lastRequest(): ChatRequestModel | undefined { + return this._requests.at(-1); + } + private _creationDate: number; get creationDate(): number { return this._creationDate; diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.contribution.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.contribution.ts index 8d9a0869da9..33c572bb0d4 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChat.contribution.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChat.contribution.ts @@ -107,6 +107,7 @@ registerAction2(InlineChatActions.ViewInChatAction); registerAction2(InlineChatActions.ToggleDiffForChange); registerAction2(InlineChatActions.AcceptChanges); +registerAction2(InlineChatActions.ReportIssueAction); registerAction2(InlineChatActions.CopyRecordings); const workbenchContributionsRegistry = Registry.as(WorkbenchExtensions.Workbench); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts index 3ca378f4302..cb1d4633c9d 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts @@ -11,7 +11,7 @@ import { EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/diffEditor/em import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/codeEditor/embeddedCodeEditorWidget'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { InlineChatController, InlineChatRunOptions } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController'; -import { ACTION_ACCEPT_CHANGES, CTX_INLINE_CHAT_HAS_AGENT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_VISIBLE, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_USER_DID_EDIT, CTX_INLINE_CHAT_DOCUMENT_CHANGED, CTX_INLINE_CHAT_EDIT_MODE, EditMode, MENU_INLINE_CHAT_WIDGET_STATUS, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS, CTX_INLINE_CHAT_RESPONSE_TYPE, InlineChatResponseType, ACTION_REGENERATE_RESPONSE, MENU_INLINE_CHAT_CONTENT_STATUS, ACTION_VIEW_IN_CHAT, ACTION_TOGGLE_DIFF, CTX_INLINE_CHAT_CHANGE_HAS_DIFF, CTX_INLINE_CHAT_CHANGE_SHOWS_DIFF, MENU_INLINE_CHAT_ZONE } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; +import { ACTION_ACCEPT_CHANGES, CTX_INLINE_CHAT_HAS_AGENT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_VISIBLE, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_USER_DID_EDIT, CTX_INLINE_CHAT_DOCUMENT_CHANGED, CTX_INLINE_CHAT_EDIT_MODE, EditMode, MENU_INLINE_CHAT_WIDGET_STATUS, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS, CTX_INLINE_CHAT_RESPONSE_TYPE, InlineChatResponseType, ACTION_REGENERATE_RESPONSE, MENU_INLINE_CHAT_CONTENT_STATUS, ACTION_VIEW_IN_CHAT, ACTION_TOGGLE_DIFF, CTX_INLINE_CHAT_CHANGE_HAS_DIFF, CTX_INLINE_CHAT_CHANGE_SHOWS_DIFF, MENU_INLINE_CHAT_ZONE, CTX_INLINE_CHAT_SUPPORT_REPORT_ISSUE, ACTION_REPORT_ISSUE } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; import { localize, localize2 } from 'vs/nls'; import { Action2, IAction2Options } from 'vs/platform/actions/common/actions'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; @@ -554,3 +554,23 @@ export class ToggleDiffForChange extends AbstractInlineChatAction { ctrl.toggleDiff(); } } + +export class ReportIssueAction extends AbstractInlineChatAction { + constructor() { + super({ + id: ACTION_REPORT_ISSUE, + title: localize2('reportIssue', 'Report Issue'), + icon: Codicon.report, + menu: [{ + id: MENU_INLINE_CHAT_WIDGET_STATUS, + group: '0_main', + order: 6, + when: ContextKeyExpr.and(CTX_INLINE_CHAT_VISIBLE, CTX_INLINE_CHAT_SUPPORT_REPORT_ISSUE, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS.negate()) + }] + }); + } + + override runInlineChatCommand(_accessor: ServicesAccessor, ctrl: InlineChatController): void { + ctrl.reportIssue(); + } +} diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts index 326feed38d8..19f8fe9d68b 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts @@ -42,7 +42,7 @@ import { InlineChatContentWidget } from 'vs/workbench/contrib/inlineChat/browser import { EmptyResponse, ErrorResponse, ReplyResponse, Session, StashedSession } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession'; import { InlineChatError } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl'; import { EditModeStrategy, IEditObserver, LiveStrategy, PreviewStrategy, ProgressingEditsOptions } from 'vs/workbench/contrib/inlineChat/browser/inlineChatStrategies'; -import { CTX_INLINE_CHAT_EDITING, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS, CTX_INLINE_CHAT_RESPONSE_TYPE, CTX_INLINE_CHAT_USER_DID_EDIT, CTX_INLINE_CHAT_VISIBLE, EditMode, INLINE_CHAT_ID, InlineChatConfigKeys, InlineChatResponseType } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; +import { CTX_INLINE_CHAT_EDITING, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS, CTX_INLINE_CHAT_RESPONSE_TYPE, CTX_INLINE_CHAT_SUPPORT_REPORT_ISSUE, CTX_INLINE_CHAT_USER_DID_EDIT, CTX_INLINE_CHAT_VISIBLE, EditMode, INLINE_CHAT_ID, InlineChatConfigKeys, InlineChatResponseType } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/services/notebookEditorService'; import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IViewsService } from 'vs/workbench/services/views/common/viewsService'; @@ -114,6 +114,7 @@ export class InlineChatController implements IEditorContribution { private readonly _ctxResponseType: IContextKey; private readonly _ctxUserDidEdit: IContextKey; private readonly _ctxRequestInProgress: IContextKey; + private readonly _ctxSupportsReportIssue: IContextKey; private readonly _messages = this._store.add(new Emitter()); protected readonly _onDidEnterState = this._store.add(new Emitter()); @@ -153,6 +154,7 @@ export class InlineChatController implements IEditorContribution { this._ctxUserDidEdit = CTX_INLINE_CHAT_USER_DID_EDIT.bindTo(contextKeyService); this._ctxResponseType = CTX_INLINE_CHAT_RESPONSE_TYPE.bindTo(contextKeyService); this._ctxRequestInProgress = CTX_INLINE_CHAT_REQUEST_IN_PROGRESS.bindTo(contextKeyService); + this._ctxSupportsReportIssue = CTX_INLINE_CHAT_SUPPORT_REPORT_ISSUE.bindTo(contextKeyService); this._ui = new Lazy(() => { @@ -545,11 +547,13 @@ export class InlineChatController implements IEditorContribution { this._ctxRequestInProgress.set(true); const { chatModel } = this._session; - const request: IChatRequestModel | undefined = chatModel.getRequests().at(-1); + const request = chatModel.lastRequest; assertType(request); assertType(request.response); + this._ctxSupportsReportIssue.set(request.response.agent?.metadata.supportIssueReporting ?? false); + this._showWidget(options, false); this._ui.value.zone.widget.selectAll(false); this._ui.value.zone.widget.updateInfo(''); @@ -1075,7 +1079,7 @@ export class InlineChatController implements IEditorContribution { } async cancelSession() { - const response = this._session?.chatModel.getRequests().at(-1)?.response; + const response = this._session?.chatModel.lastRequest?.response; if (response) { this._chatService.notifyUserAction({ sessionId: response.session.sessionId, @@ -1105,6 +1109,20 @@ export class InlineChatController implements IEditorContribution { } } + reportIssue() { + const response = this._session?.chatModel.lastRequest?.response; + if (response) { + this._chatService.notifyUserAction({ + sessionId: response.session.sessionId, + requestId: response.requestId, + agentId: response.agent?.id, + command: response.slashCommand?.name, + result: response.result, + action: { kind: 'bug' } + }); + } + } + unstashLastSession(): Session | undefined { const result = this._stashedSession.value?.unstash(); if (result) { diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts index 0f5da62da94..992284950bf 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts @@ -14,7 +14,7 @@ import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/browser/zoneWidget'; import { localize } from 'vs/nls'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ACTION_ACCEPT_CHANGES, ACTION_REGENERATE_RESPONSE, ACTION_TOGGLE_DIFF, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, EditMode, InlineChatConfigKeys, MENU_INLINE_CHAT_WIDGET_STATUS } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; +import { ACTION_REGENERATE_RESPONSE, ACTION_REPORT_ISSUE, ACTION_TOGGLE_DIFF, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, EditMode, InlineChatConfigKeys, MENU_INLINE_CHAT_WIDGET_STATUS } from 'vs/workbench/contrib/inlineChat/common/inlineChat'; import { EditorBasedInlineChatWidget } from './inlineChatWidget'; import { isEqual } from 'vs/base/common/resources'; import { StableEditorBottomScrollState } from 'vs/editor/browser/stableEditorScroll'; @@ -53,10 +53,8 @@ export class InlineChatZoneWidget extends ZoneWidget { options: { buttonConfigProvider: (action, index) => { const isSecondary = index > 0; - if (new Set([ACTION_REGENERATE_RESPONSE, ACTION_TOGGLE_DIFF]).has(action.id)) { + if (new Set([ACTION_REGENERATE_RESPONSE, ACTION_TOGGLE_DIFF, ACTION_REPORT_ISSUE]).has(action.id)) { return { isSecondary, showIcon: true, showLabel: false }; - } else if (action.id === ACTION_ACCEPT_CHANGES) { - return { isSecondary }; } else { return { isSecondary }; } diff --git a/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts b/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts index 4ed5a7c194e..df012aae4d1 100644 --- a/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts +++ b/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts @@ -114,12 +114,15 @@ export const CTX_INLINE_CHAT_EDIT_MODE = new RawContextKey('config.inl export const CTX_INLINE_CHAT_REQUEST_IN_PROGRESS = new RawContextKey('inlineChatRequestInProgress', false, localize('inlineChatRequestInProgress', "Whether an inline chat request is currently in progress")); export const CTX_INLINE_CHAT_RESPONSE_TYPE = new RawContextKey('inlineChatResponseType', InlineChatResponseType.None, localize('inlineChatResponseTypes', "What type was the responses have been receieved, nothing yet, just messages, or messaged and local edits")); +export const CTX_INLINE_CHAT_SUPPORT_REPORT_ISSUE = new RawContextKey('inlineChatSupportReportIssue', false, localize('inlineChatSupportReportIssue', "Whether inline chat supports reporting issues")); + // --- (selected) action identifier export const ACTION_ACCEPT_CHANGES = 'inlineChat.acceptChanges'; export const ACTION_REGENERATE_RESPONSE = 'inlineChat.regenerate'; export const ACTION_VIEW_IN_CHAT = 'inlineChat.viewInChat'; export const ACTION_TOGGLE_DIFF = 'inlineChat.toggleDiff'; +export const ACTION_REPORT_ISSUE = 'inlineChat.reportIssue'; // --- menus