diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index 8faac4fb00f..bd917a0fd9a 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -11,7 +11,7 @@ import { Codicon } from '../../../../base/common/codicons.js'; import { toErrorMessage } from '../../../../base/common/errorMessage.js'; import { Emitter, Event } from '../../../../base/common/event.js'; import { FuzzyScore } from '../../../../base/common/filters.js'; -import { MarkdownString } from '../../../../base/common/htmlContent.js'; +import { IMarkdownString, MarkdownString } from '../../../../base/common/htmlContent.js'; import { Iterable } from '../../../../base/common/iterator.js'; import { combinedDisposable, Disposable, DisposableStore, IDisposable, MutableDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; import { ResourceSet } from '../../../../base/common/map.js'; @@ -64,7 +64,7 @@ import { ChatEditorOptions } from './chatOptions.js'; import './media/chat.css'; import './media/chatAgentHover.css'; import './media/chatViewWelcome.css'; -import { ChatViewWelcomePart, IChatSuggestedPrompts, IChatViewWelcomeContent } from './viewsWelcome/chatViewWelcomeController.js'; +import { ChatViewWelcomePart, IChatViewWelcomeContent } from './viewsWelcome/chatViewWelcomeController.js'; import { MicrotaskDelay } from '../../../../base/common/symbols.js'; import { IChatRequestVariableEntry, ChatRequestVariableSet as ChatRequestVariableSet, isPromptFileVariableEntry, toPromptFileVariableEntry, PromptFileVariableKind } from '../common/chatVariableEntries.js'; import { PromptsConfig } from '../common/promptSyntax/config/config.js'; @@ -734,9 +734,6 @@ export class ChatWidget extends Disposable implements IChatWidget { const numItems = this.viewModel?.getItems().length ?? 0; if (!numItems) { dom.clearNode(this.welcomeMessageContainer); - const defaultAgent = this.chatAgentService.getDefaultAgent(this.location, this.input.currentModeKind); - const additionalMessage = defaultAgent?.metadata.additionalWelcomeMessage; - const startupExpValue = startupExpContext.getValue(this.contextKeyService); let welcomeContent: IChatViewWelcomeContent; if (startupExpValue === StartupExperimentGroup.MaximizedChat @@ -746,15 +743,17 @@ export class ChatWidget extends Disposable implements IChatWidget { this.container.classList.add('experimental-welcome-view'); } else { + const defaultAgent = this.chatAgentService.getDefaultAgent(this.location, this.input.currentModeKind); + const additionalMessage = defaultAgent?.metadata.additionalWelcomeMessage; const tips = this.input.currentModeKind === ChatModeKind.Ask ? new MarkdownString(localize('chatWidget.tips', "{0} or type {1} to attach context\n\n{2} to chat with extensions\n\nType {3} to use commands", '$(attach)', '#', '$(mention)', '/'), { supportThemeIcons: true }) : new MarkdownString(localize('chatWidget.tips.withoutParticipants', "{0} or type {1} to attach context", '$(attach)', '#'), { supportThemeIcons: true }); - welcomeContent = this.getWelcomeViewContent(); + welcomeContent = this.getWelcomeViewContent(additionalMessage); welcomeContent.tips = tips; } this.welcomePart.value = this.instantiationService.createInstance( ChatViewWelcomePart, - { ...welcomeContent, additionalMessage }, + welcomeContent, { location: this.location, isWidgetAgentWelcomeViewContent: this.input?.currentModeKind === ChatModeKind.Agent @@ -769,58 +768,44 @@ export class ChatWidget extends Disposable implements IChatWidget { } } - private getWelcomeViewContent(): IChatViewWelcomeContent { + private getWelcomeViewContent(additionalMessage: string | IMarkdownString | undefined): IChatViewWelcomeContent { const baseMessage = localize('chatMessage', "Copilot is powered by AI, so mistakes are possible. Review output carefully before use."); if (this.input.currentModeKind === ChatModeKind.Ask) { return { title: localize('chatDescription', "Ask Copilot"), message: new MarkdownString(baseMessage), - icon: Codicon.copilotLarge + icon: Codicon.copilotLarge, + additionalMessage, }; } else if (this.input.currentModeKind === ChatModeKind.Edit) { return { title: localize('editsTitle', "Edit with Copilot"), message: new MarkdownString(localize('editsMessage', "Start your editing session by defining a set of files that you want to work with. Then ask Copilot for the changes you want to make.") + `\n\n${baseMessage}`), - icon: Codicon.copilotLarge + icon: Codicon.copilotLarge, + additionalMessage }; } else { return { title: localize('editsTitle', "Edit with Copilot"), message: new MarkdownString(localize('agentMessage', "Ask Copilot to edit your files in [agent mode]({0}). Copilot will automatically use multiple requests to pick files to edit, run terminal commands, and iterate on errors.", 'https://aka.ms/vscode-copilot-agent') + `\n\n${baseMessage}`), - icon: Codicon.copilotLarge + icon: Codicon.copilotLarge, + additionalMessage }; } } private getExpWelcomeViewContent(): IChatViewWelcomeContent { - const baseMessage = localize('chatMessage', "Copilot is powered by AI, so mistakes are possible. Review output carefully before use."); - const welcomeContent = { - title: localize('expChatTitle', 'Get Started with VS Code'), - message: new MarkdownString(baseMessage), + const welcomeContent: IChatViewWelcomeContent = { + title: localize('expChatTitle', 'Welcome to Copilot'), + message: new MarkdownString(localize('expchatMessage', "Let's get started")), icon: Codicon.copilotLarge, - suggestedPrompts: this.getExpSuggestedPrompts(), inputPart: this.inputPart.element, + additionalMessage: localize('expChatAdditionalMessage', "Review output carefully before use."), + isExperimental: true }; return welcomeContent; } - private getExpSuggestedPrompts(): IChatSuggestedPrompts[] { - - return [ - { - icon: Codicon.vscode, - label: localize('chatWidget.suggestedPrompts.gettingStarted', "Ask @vscode"), - prompt: '@vscode Help me get started with VS Code?', - }, - { - icon: Codicon.newFolder, - label: localize('chatWidget.suggestedPrompts.newProject', "Create a #new Project"), - prompt: '#new Create a new project for me', - } - ]; - } - - private async renderChatEditingSessionState() { if (!this.input) { return; diff --git a/src/vs/workbench/contrib/chat/browser/media/chatViewWelcome.css b/src/vs/workbench/contrib/chat/browser/media/chatViewWelcome.css index 23b7ce84566..872583659e4 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chatViewWelcome.css +++ b/src/vs/workbench/contrib/chat/browser/media/chatViewWelcome.css @@ -23,6 +23,11 @@ .interactive-session .experimental-welcome-view & > .chat-welcome-view-input-part { max-width: 650px; + margin-bottom: 48px; +} + +.interactive-session.experimental-welcome-view .chat-input-toolbars > .chat-input-toolbar > div { + display: none; } /* Container for ChatViewPane welcome view */ @@ -102,44 +107,21 @@ div.chat-welcome-view { } } - & > .chat-welcome-view-suggested-prompts { - display: flex; - flex-wrap: wrap; - gap: 10px; - justify-content: center; - margin-top: 15px; + & > .chat-welcome-experimental-view-message { + text-align: center; + max-width: 350px; + padding: 0 20px 32px; + font-size: 16px; - > .chat-welcome-view-suggested-prompt { - display: flex; - align-items: center; - padding: 0 4px; - border-radius: 8px; - background-color: var(--vscode-editorWidget-background); - cursor: pointer; - border: 1px solid var(--vscode-chat-requestBorder, var(--vscode-input-background, transparent)); - border-radius: 4px; - gap: 2px; - max-width: 100%; - width: fit-content; - - > .chat-welcome-view-suggested-prompt-icon { - display: flex; - align-items: center; - margin-right: 8px; - font-size: 4px; - color: var(--vscode-icon-foreground) !important; - align-items: center; - } - - > .chat-welcome-view-suggested-prompt-label { - font-size: 14px; - color: var(--vscode-editorWidget-foreground); - } - } - - > .chat-welcome-view-suggested-prompt:hover { - background-color: var(--vscode-list-hoverBackground); - border-color: var(--vscode-focusBorder); + a { + color: var(--vscode-descriptionForeground); } } + + & > .chat-welcome-view-experimental-additional-message { + font-size: 12px; + color: var(--vscode-disabledForeground); + text-align: center; + max-width: 400px; + } } diff --git a/src/vs/workbench/contrib/chat/browser/viewsWelcome/chatViewWelcomeController.ts b/src/vs/workbench/contrib/chat/browser/viewsWelcome/chatViewWelcomeController.ts index 7b63aae3a9f..fc1bdc60794 100644 --- a/src/vs/workbench/contrib/chat/browser/viewsWelcome/chatViewWelcomeController.ts +++ b/src/vs/workbench/contrib/chat/browser/viewsWelcome/chatViewWelcomeController.ts @@ -19,8 +19,6 @@ import { IOpenerService } from '../../../../../platform/opener/common/opener.js' import { defaultButtonStyles } from '../../../../../platform/theme/browser/defaultStyles.js'; import { ChatAgentLocation } from '../../common/constants.js'; import { chatViewsWelcomeRegistry, IChatViewsWelcomeDescriptor } from './chatViewsWelcome.js'; -import { IChatWidgetService } from '../chat.js'; -import { ITelemetryService } from '../../../../../platform/telemetry/common/telemetry.js'; const $ = dom.$; @@ -115,13 +113,7 @@ export interface IChatViewWelcomeContent { additionalMessage?: string | IMarkdownString; tips?: IMarkdownString; inputPart?: HTMLElement; - suggestedPrompts?: IChatSuggestedPrompts[]; -} - -export interface IChatSuggestedPrompts { - icon?: ThemeIcon; - label: string; - prompt: string; + isExperimental?: boolean; } export interface IChatViewWelcomeRenderOptions { @@ -139,8 +131,6 @@ export class ChatViewWelcomePart extends Disposable { @IOpenerService private openerService: IOpenerService, @IInstantiationService private instantiationService: IInstantiationService, @ILogService private logService: ILogService, - @IChatWidgetService private chatWidgetService: IChatWidgetService, - @ITelemetryService private telemetryService: ITelemetryService, ) { super(); this.element = dom.$('.chat-welcome-view'); @@ -165,57 +155,32 @@ export class ChatViewWelcomePart extends Disposable { } // Message - const message = dom.append(this.element, $('.chat-welcome-view-message')); + const message = dom.append(this.element, content.isExperimental ? $('.chat-welcome-experimental-view-message') : $('.chat-welcome-view-message')); if (typeof content.message === 'function') { dom.append(message, content.message(this._register(new DisposableStore()))); } else { const messageResult = this.renderMarkdownMessageContent(renderer, content.message, options); dom.append(message, messageResult.element); - } - // Additional message - if (typeof content.additionalMessage === 'string') { - const element = $(''); - element.textContent = content.additionalMessage; - dom.append(message, element); - } else if (content.additionalMessage) { - const additionalMessageResult = this.renderMarkdownMessageContent(renderer, content.additionalMessage, options); - dom.append(message, additionalMessageResult.element); - } - - if (content.inputPart) { + if (content.isExperimental && content.inputPart) { + content.inputPart.querySelector('.chat-attachments-container')?.remove(); dom.append(this.element, content.inputPart); - } - - if (content.suggestedPrompts && content.suggestedPrompts.length) { - - // create a tile with icon and label for each suggested promot - const suggestedPromptsContainer = dom.append(this.element, $('.chat-welcome-view-suggested-prompts')); - for (const prompt of content.suggestedPrompts) { - const promptElement = dom.append(suggestedPromptsContainer, $('.chat-welcome-view-suggested-prompt')); - if (prompt.icon) { - const iconElement = dom.append(promptElement, $('.chat-welcome-view-suggested-prompt-icon')); - iconElement.appendChild(renderIcon(prompt.icon)); - } - const labelElement = dom.append(promptElement, $('.chat-welcome-view-suggested-prompt-label')); - labelElement.textContent = prompt.label; - this._register(dom.addDisposableListener(promptElement, dom.EventType.CLICK, () => { - - type SuggestedPromptClickEvent = { suggestedPrompt: string }; - - type SuggestedPromptClickData = { - owner: 'bhavyaus'; - comment: 'Event used to gain insights into when suggested prompts are clicked.'; - suggestedPrompt: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The suggested prompt clicked.' }; - }; - - this.telemetryService.publicLog2('chat.clickedSuggestedPrompt', { - suggestedPrompt: prompt.prompt, - }); - - this.chatWidgetService.lastFocusedWidget?.setInput(prompt.prompt); - })); + if (typeof content.additionalMessage === 'string') { + const additionalMsg = $('.chat-welcome-view-experimental-additional-message'); + additionalMsg.textContent = content.additionalMessage; + dom.append(this.element, additionalMsg); + } + // also append telemetry message if available + } else { + // Additional message + if (typeof content.additionalMessage === 'string') { + const element = $(''); + element.textContent = content.additionalMessage; + dom.append(message, element); + } else if (content.additionalMessage) { + const additionalMessageResult = this.renderMarkdownMessageContent(renderer, content.additionalMessage, options); + dom.append(message, additionalMessageResult.element); } }