-
Notifications
You must be signed in to change notification settings - Fork 42k
Read chat responses aloud #331859
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Read chat responses aloud #331859
Changes from all commits
4e3a1d6
9da57c8
c79130e
49881ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -636,6 +636,20 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch | |
| private readonly pendingStickyScrollStateRefresh = this._register(new MutableDisposable<IDisposable>()); | ||
| private readonly templateDataByRow = new WeakMap<HTMLElement, IChatListItemTemplate>(); | ||
|
|
||
| private static readonly synthesisInProgressKeys = new Set([ChatContextKeys.synthesisInProgressItemId.key]); | ||
|
|
||
| /** | ||
| * Whether `element` is the response that is currently being read aloud, so | ||
| * that only its footer offers to stop reading. | ||
| */ | ||
| private isSynthesisInProgressFor(element: ChatTreeItem | undefined): boolean { | ||
| if (!element || !isResponseVM(element)) { | ||
| return false; | ||
| } | ||
|
|
||
| return this.contextKeyService.getContextKeyValue<string>(ChatContextKeys.synthesisInProgressItemId.key) === element.id; | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed in principle, but leaving this one for now and happy to be told otherwise. The state is owned by That seemed like more than I wanted to add while the PR is still blocked on the endpoint, but I'm glad to do it if you'd prefer it in this change. |
||
| } | ||
|
|
||
| /** Track pending question carousels by session resource for auto-skip on chat submission */ | ||
| private readonly pendingQuestionCarousels = new ResourceMap<Set<ChatQuestionCarouselPart>>(); | ||
| private readonly _notifiedQuestionCarousels = new Set<string>(); | ||
|
|
@@ -1169,6 +1183,15 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch | |
| const template: IChatListItemTemplate = { header, avatarContainer, requestHover, username, detail, value, requestTimestampContainer, rowContainer, elementDisposables, templateDisposables, contextKeyService, instantiationService: scopedInstantiationService, agentHover, titleToolbar, footerToolbar, footerToolbarContainer, footerDetailsContainer, disabledOverlay, checkpointToolbar, checkpointRestoreToolbar, checkpointContainer, checkpointRestoreContainer, completedResponseDisclosureDisposables, responseTokenStatsHover, feedbackSurveyWidget }; | ||
| this.templateDataByRow.set(rowContainer, template); | ||
|
|
||
| // Only the response that is being read aloud shows a stop button, so keep | ||
| // this row in sync while it stays rendered. | ||
| const itemSynthesisInProgress = ChatContextKeys.itemSynthesisInProgress.bindTo(contextKeyService); | ||
| templateDisposables.add(this.contextKeyService.onDidChangeContext(e => { | ||
| if (e.affectsSome(ChatListItemRenderer.synthesisInProgressKeys)) { | ||
| itemSynthesisInProgress.set(this.isSynthesisInProgressFor(template.currentElement)); | ||
| } | ||
| })); | ||
|
|
||
| templateDisposables.add(this._onDidUpdateViewModel.event(() => { | ||
| if (!template.currentElement || !this.viewModel?.sessionResource || !isEqual(template.currentElement.sessionResource, this.viewModel.sessionResource)) { | ||
| this.clearRenderedParts(template); | ||
|
|
@@ -1320,6 +1343,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch | |
|
|
||
| ChatContextKeys.isResponse.bindTo(templateData.contextKeyService).set(isResponseVM(element)); | ||
| ChatContextKeys.itemId.bindTo(templateData.contextKeyService).set(element.id); | ||
| ChatContextKeys.itemSynthesisInProgress.bindTo(templateData.contextKeyService).set(this.isSynthesisInProgressFor(element)); | ||
| ChatContextKeys.isRequest.bindTo(templateData.contextKeyService).set(isRequestVM(element)); | ||
| ChatContextKeys.isFirstRequest.bindTo(templateData.contextKeyService).set(isRequestVM(element) && this.viewModel?.model.getRequests()[0]?.id === element.id); | ||
| ChatContextKeys.isPendingRequest.bindTo(templateData.contextKeyService).set(isRequestVM(element) && !!element.pendingKind); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| /*--------------------------------------------------------------------------------------------- | ||
| * Copyright (c) Microsoft Corporation. All rights reserved. | ||
| * Licensed under the MIT License. See License.txt in the project root for license information. | ||
| *--------------------------------------------------------------------------------------------*/ | ||
|
|
||
| import { registerAction2 } from '../../../../../platform/actions/common/actions.js'; | ||
| import { ReadChatResponseAloud, StopReadAloud, StopReadChatItemAloud } from './voiceChatActions.js'; | ||
|
|
||
| /** | ||
| * Registers reading chat responses aloud. Kept apart from the voice chat actions | ||
| * so that windows which do not offer voice chat, such as the Agents window, can | ||
| * still read responses aloud. | ||
| */ | ||
| export function registerReadAloudActions(): void { | ||
| registerAction2(ReadChatResponseAloud); | ||
| registerAction2(StopReadChatItemAloud); | ||
| registerAction2(StopReadAloud); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, this was a deadlock: no speech provider and no platform synthesizer meant the settings were never registered, so
Set Up Read Aloudcould not write the endpoint, so the engine could never become available. Fixed in c80f0c4 by registering the endpoint and voice settings statically, leaving only the speech-provider-dependent ones behind the gate.