Skip to content

Commit 90d169c

Browse files
committed
add audio cues and alert with response
1 parent 8af267c commit 90d169c

File tree

5 files changed

+55
-36
lines changed

5 files changed

+55
-36
lines changed

src/vs/workbench/contrib/chat/browser/chat.contribution.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { ChatTreeItem, IChatAccessibilityService, IChatWidget, IChatWidgetServic
2626
import { ChatContributionService } from 'vs/workbench/contrib/chat/browser/chatContributionServiceImpl';
2727
import { ChatEditor, IChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatEditor';
2828
import { ChatEditorInput, ChatEditorInputSerializer } from 'vs/workbench/contrib/chat/browser/chatEditorInput';
29-
import { ChatAccessibilityService, ChatWidgetService } from 'vs/workbench/contrib/chat/browser/chatWidget';
29+
import { ChatWidgetService } from 'vs/workbench/contrib/chat/browser/chatWidget';
3030
import 'vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib';
3131
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
3232
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
@@ -42,6 +42,7 @@ import { AccessibleViewType, IAccessibleViewService } from 'vs/workbench/contrib
4242
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
4343
import { IChatResponseViewModel, isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
4444
import { CONTEXT_IN_CHAT_SESSION } from 'vs/workbench/contrib/chat/common/chatContextKeys';
45+
import { ChatAccessibilityService } from 'vs/workbench/contrib/chat/browser/chatAccessibilityService';
4546

4647
// Register configuration
4748
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);

src/vs/workbench/contrib/chat/browser/chat.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export interface IChatWidgetService {
3434
export interface IChatAccessibilityService {
3535
readonly _serviceBrand: undefined;
3636
acceptRequest(): void;
37-
acceptResponse(response?: IChatResponseViewModel): void;
37+
acceptResponse(response?: IChatResponseViewModel | string): void;
3838
}
3939

4040
export interface IChatCodeBlockInfo {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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 { status, alert } from 'vs/base/browser/ui/aria/aria';
7+
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
8+
import { AudioCue, AudioCueGroupId, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService';
9+
import { IChatAccessibilityService } from 'vs/workbench/contrib/chat/browser/chat';
10+
import { IChatResponseViewModel } from 'vs/workbench/contrib/chat/common/chatViewModel';
11+
12+
const CHAT_RESPONSE_PENDING_AUDIO_CUE_LOOP_MS = 5000;
13+
export class ChatAccessibilityService extends Disposable implements IChatAccessibilityService {
14+
declare readonly _serviceBrand: undefined;
15+
16+
private _responsePendingAudioCue: IDisposable | undefined;
17+
18+
constructor(@IAudioCueService private readonly _audioCueService: IAudioCueService) {
19+
super();
20+
}
21+
acceptRequest(): void {
22+
this._audioCueService.playAudioCue(AudioCue.chatRequestSent, true);
23+
this._responsePendingAudioCue = this._audioCueService.playAudioCueLoop(AudioCue.chatResponsePending, CHAT_RESPONSE_PENDING_AUDIO_CUE_LOOP_MS);
24+
}
25+
acceptResponse(response?: IChatResponseViewModel | string): void {
26+
const isPanelChat = typeof response !== 'string';
27+
this._responsePendingAudioCue?.dispose();
28+
this._audioCueService.playRandomAudioCue(AudioCueGroupId.chatResponseReceived, true);
29+
if (!response) {
30+
return;
31+
}
32+
const errorDetails = isPanelChat && response.errorDetails ? ` ${response.errorDetails.message}` : '';
33+
const content = isPanelChat ? response.response.value : response;
34+
isPanelChat ? status(content + errorDetails) : alert(content);
35+
}
36+
}
37+
38+

src/vs/workbench/contrib/chat/browser/chatWidget.ts

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import * as dom from 'vs/base/browser/dom';
7-
import { status } from 'vs/base/browser/ui/aria/aria';
87
import { ITreeContextMenuEvent, ITreeElement } from 'vs/base/browser/ui/tree/tree';
98
import { CancellationToken } from 'vs/base/common/cancellation';
109
import { Emitter } from 'vs/base/common/event';
@@ -16,7 +15,6 @@ import 'vs/css!./media/chat';
1615
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
1716
import { localize } from 'vs/nls';
1817
import { MenuId } from 'vs/platform/actions/common/actions';
19-
import { AudioCue, AudioCueGroupId, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService';
2018
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
2119
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
2220
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -518,30 +516,3 @@ export class ChatWidgetService implements IChatWidgetService {
518516
);
519517
}
520518
}
521-
522-
523-
const CHAT_RESPONSE_PENDING_AUDIO_CUE_LOOP_MS = 5000;
524-
export class ChatAccessibilityService extends Disposable implements IChatAccessibilityService {
525-
526-
declare readonly _serviceBrand: undefined;
527-
528-
private _responsePendingAudioCue: IDisposable | undefined;
529-
530-
constructor(@IAudioCueService private readonly _audioCueService: IAudioCueService) {
531-
super();
532-
}
533-
acceptRequest(): void {
534-
this._audioCueService.playAudioCue(AudioCue.chatRequestSent, true);
535-
this._responsePendingAudioCue = this._audioCueService.playAudioCueLoop(AudioCue.chatResponsePending, CHAT_RESPONSE_PENDING_AUDIO_CUE_LOOP_MS);
536-
}
537-
acceptResponse(response?: IChatResponseViewModel): void {
538-
this._responsePendingAudioCue?.dispose();
539-
this._audioCueService.playRandomAudioCue(AudioCueGroupId.chatResponseReceived, true);
540-
if (!response) {
541-
return;
542-
}
543-
const errorDetails = response.errorDetails ? ` ${response.errorDetails.message}` : '';
544-
status(response.response.value + errorDetails);
545-
}
546-
}
547-

src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import { EditResponse, EmptyResponse, ErrorResponse, ExpansionState, IInlineChat
3232
import { EditModeStrategy, LivePreviewStrategy, LiveStrategy, PreviewStrategy } from 'vs/workbench/contrib/inlineChat/browser/inlineChatStrategies';
3333
import { InlineChatZoneWidget } from 'vs/workbench/contrib/inlineChat/browser/inlineChatWidget';
3434
import { CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST, CTX_INLINE_CHAT_LAST_FEEDBACK, IInlineChatRequest, IInlineChatResponse, INLINE_CHAT_ID, EditMode, InlineChatResponseFeedbackKind, CTX_INLINE_CHAT_LAST_RESPONSE_TYPE, InlineChatResponseType, CTX_INLINE_CHAT_DID_EDIT, CTX_INLINE_CHAT_HAS_STASHED_SESSION } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
35-
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
35+
import { IChatAccessibilityService, IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
3636
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService';
3737
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/services/notebookEditorService';
3838
import { CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon';
@@ -114,6 +114,7 @@ export class InlineChatController implements IEditorContribution {
114114
@IContextKeyService contextKeyService: IContextKeyService,
115115
@IAccessibilityService private readonly _accessibilityService: IAccessibilityService,
116116
@IKeybindingService private readonly _keybindingService: IKeybindingService,
117+
@IChatAccessibilityService private readonly _chatAccessibilityService: IChatAccessibilityService
117118
) {
118119
this._ctxHasActiveRequest = CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST.bindTo(contextKeyService);
119120
this._ctxDidEdit = CTX_INLINE_CHAT_DID_EDIT.bindTo(contextKeyService);
@@ -504,6 +505,7 @@ export class InlineChatController implements IEditorContribution {
504505
selection: this._editor.getSelection(),
505506
wholeRange: this._activeSession.wholeRange.value,
506507
};
508+
this._chatAccessibilityService.acceptRequest();
507509
const task = this._activeSession.provider.provideResponse(this._activeSession.session, request, requestCts.token);
508510
this._log('request started', this._activeSession.provider.debugName, this._activeSession.session, request);
509511

@@ -514,7 +516,6 @@ export class InlineChatController implements IEditorContribution {
514516
this._zone.value.widget.updateInfo(!this._activeSession.lastExchange ? localize('thinking', "Thinking\u2026") : '');
515517
this._ctxHasActiveRequest.set(true);
516518
reply = await raceCancellationError(Promise.resolve(task), requestCts.token);
517-
518519
if (reply?.type === 'message') {
519520
response = new MarkdownResponse(this._activeSession.textModelN.uri, reply);
520521
} else if (reply) {
@@ -594,19 +595,23 @@ export class InlineChatController implements IEditorContribution {
594595
const { response } = this._activeSession.lastExchange!;
595596
this._showWidget(false);
596597

598+
let status: string | undefined;
599+
597600
this._ctxLastResponseType.set(response instanceof EditResponse || response instanceof MarkdownResponse
598601
? response.raw.type
599602
: undefined);
600603

601604
if (response instanceof EmptyResponse) {
602605
// show status message
603-
this._zone.value.widget.updateStatus(localize('empty', "No results, please refine your input and try again"), { classes: ['warn'] });
606+
status = localize('empty', "No results, please refine your input and try again");
607+
this._zone.value.widget.updateStatus(status, { classes: ['warn'] });
604608
return State.WAIT_FOR_INPUT;
605609

606610
} else if (response instanceof ErrorResponse) {
607611
// show error
608612
if (!response.isCancellation) {
609-
this._zone.value.widget.updateStatus(response.message, { classes: ['error'] });
613+
status = response.message;
614+
this._zone.value.widget.updateStatus(status, { classes: ['error'] });
610615
}
611616

612617
} else if (response instanceof MarkdownResponse) {
@@ -615,6 +620,7 @@ export class InlineChatController implements IEditorContribution {
615620
this._zone.value.widget.updateStatus('');
616621
this._zone.value.widget.updateMarkdownMessage(renderedMarkdown.element);
617622
this._zone.value.widget.updateToolbar(true);
623+
status = renderedMarkdown.element?.textContent ?? '';
618624
this._activeSession.lastExpansionState = this._zone.value.widget.expansionState;
619625

620626
} else if (response instanceof EditResponse) {
@@ -626,10 +632,13 @@ export class InlineChatController implements IEditorContribution {
626632
if (!canContinue) {
627633
return State.ACCEPT;
628634
}
629-
635+
// TODO: summarize proposed changes
636+
status = 'navigate to the diff editor to review proposed changes.';
630637
await this._strategy.renderChanges(response);
631638
}
632639

640+
this._chatAccessibilityService.acceptResponse(status);
641+
633642
return State.WAIT_FOR_INPUT;
634643
}
635644

0 commit comments

Comments
 (0)