Skip to content

Commit 6801571

Browse files
justschenCopilot
andauthored
chat: refine Copilot introduction banner with ExP variants (#338509)
* chat: refine Copilot introduction banner Restore the top-right dismiss action and group Learn More with Got it using standard secondary button styling. Clarify the cross-window value proposition while retaining the feedback link and persistent acknowledgement behavior. Add themed and narrow component fixtures plus regression coverage for dismissal, action layout, and button styling. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chat: add Copilot introduction experiment variants Make localized copy and button layout independent ExP treatments. Keep the approved default while allowing the original three-button feedback layout with any wording. Resolve assignments before initial exposure, log experiment triggers only when shown, and share the presentation with the comparison fixtures. Cover variant combinations, refreshes, failures, persistence, and disposal. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chat: add a complete banner variant comparison Render all eight wording and button combinations together using the production notification widget in both dark and light themes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a37ac69 commit 6801571

9 files changed

Lines changed: 576 additions & 122 deletions

File tree

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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 { Codicon } from '../../../../../base/common/codicons.js';
7+
import { localize } from '../../../../../nls.js';
8+
import { ChatInputNotificationActionKind, IChatInputNotificationCommandAction } from '../widget/input/chatInputNotificationService.js';
9+
10+
export const copilotHarnessIntroductionCopyVariants = ['current', 'capabilities', 'agent', 'original'] as const;
11+
export type CopilotHarnessIntroductionCopyVariant = typeof copilotHarnessIntroductionCopyVariants[number];
12+
13+
export const copilotHarnessIntroductionButtonVariants = ['dismiss', 'feedback'] as const;
14+
export type CopilotHarnessIntroductionButtonVariant = typeof copilotHarnessIntroductionButtonVariants[number];
15+
16+
export const copilotHarnessIntroductionLearnMoreCommandId = 'workbench.action.chat.agentsParallelWork.learnMore';
17+
export const copilotHarnessIntroductionFeedbackCommandId = 'workbench.action.chat.agentsParallelWork.feedback';
18+
19+
export function getCopilotHarnessIntroductionContent(
20+
copy: CopilotHarnessIntroductionCopyVariant = 'current',
21+
buttons: CopilotHarnessIntroductionButtonVariant = 'dismiss',
22+
): { title: string; description: string; actions: IChatInputNotificationCommandAction[]; dismissible: boolean } {
23+
const feedbackUrl = 'https://github.com/microsoft/vscode/issues';
24+
let title = localize('copilotHarnessTitle', "You're using a new Copilot experience");
25+
let description: string;
26+
switch (copy) {
27+
case 'current':
28+
description = localize('copilotHarnessDescription', "This agent harness opens up new ways to work across windows and apps. Continue as usual, and [let us know]({0}) how it goes.", feedbackUrl);
29+
break;
30+
case 'capabilities':
31+
description = localize('copilotHarnessCapabilitiesDescription', "This agent harness brings new capabilities to the way you already work. If anything seems off, [let us know]({0}).", feedbackUrl);
32+
break;
33+
case 'agent':
34+
title = localize('copilotHarnessAgentTitle', "You're using a new Copilot agent");
35+
description = localize('copilotHarnessAgentDescription', "Continue your sessions across windows and apps, without changing how you work. [Let us know]({0}) how it goes.", feedbackUrl);
36+
break;
37+
case 'original':
38+
description = localize('copilotHarnessOriginalDescription', "This new implementation unlocks exciting new capabilities, while previous agent harnesses remain available. If anything seems off, [let us know]({0}).", feedbackUrl);
39+
break;
40+
}
41+
42+
const feedbackButtons = buttons === 'feedback';
43+
const actions: IChatInputNotificationCommandAction[] = [{
44+
kind: ChatInputNotificationActionKind.Command,
45+
label: localize('learnMore', "Learn More"),
46+
telemetryActionId: 'docsLink',
47+
commandId: copilotHarnessIntroductionLearnMoreCommandId,
48+
primary: false,
49+
...(feedbackButtons ? { leading: true, outlined: true } : { filled: true }),
50+
keepOpen: true,
51+
}, {
52+
kind: ChatInputNotificationActionKind.Command,
53+
label: localize('gotIt', "{0} Got it!", `$(${Codicon.thumbsup.id})`),
54+
ariaLabel: localize('gotItAriaLabel', "Got it!"),
55+
telemetryActionId: 'thumbsUp',
56+
commandId: copilotHarnessIntroductionFeedbackCommandId,
57+
commandArgs: [true],
58+
primary: true,
59+
keepOpen: true,
60+
}];
61+
if (feedbackButtons) {
62+
actions.push({
63+
kind: ChatInputNotificationActionKind.Command,
64+
label: `$(${Codicon.thumbsdown.id})`,
65+
ariaLabel: localize('unhelpful', "Not Helpful"),
66+
iconOnly: true,
67+
tooltip: localize('unhelpfulTooltip', "Not Helpful"),
68+
telemetryActionId: 'thumbsDown',
69+
commandId: copilotHarnessIntroductionFeedbackCommandId,
70+
commandArgs: [false],
71+
primary: false,
72+
keepOpen: true,
73+
});
74+
}
75+
76+
return { title, description, actions, dismissible: !feedbackButtons };
77+
}

‎src/vs/workbench/contrib/chat/browser/widget/input/chatInputNotificationService.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ interface IChatInputNotificationActionBase {
3838
readonly iconOnly?: boolean;
3939
/** Whether the action anchors to the leading edge of a split action row. */
4040
readonly leading?: boolean;
41+
/** Whether a secondary action uses the standard filled button style instead of a ghost button. */
42+
readonly filled?: boolean;
4143
/** Whether a secondary action keeps a theme-aware border. */
4244
readonly outlined?: boolean;
4345
readonly tooltip?: string;

‎src/vs/workbench/contrib/chat/browser/widget/input/chatInputNotificationWidget.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ export class ChatInputNotificationWidget extends Disposable implements IChatInpu
355355

356356
const button = this._contentDisposables.add(new Button(actionsContainer, {
357357
...defaultButtonStyles,
358-
...(!isPrimary ? {
358+
...(!isPrimary && !action.filled ? {
359359
buttonBackground: undefined,
360360
buttonHoverBackground: undefined,
361361
buttonForeground: undefined,
@@ -370,6 +370,7 @@ export class ChatInputNotificationWidget extends Disposable implements IChatInpu
370370
button.element.classList.add('chat-input-notification-action-button');
371371
button.element.classList.toggle('icon-only', action.iconOnly === true);
372372
button.element.classList.toggle('leading', action.leading === true);
373+
button.element.classList.toggle('filled', action.filled === true);
373374
button.element.classList.toggle('outlined', action.outlined === true);
374375
button.label = action.label;
375376
const actionAriaLabel = action.ariaLabel ?? action.label;

‎src/vs/workbench/contrib/chat/browser/widget/input/media/chatInputNotificationWidget.css‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@
154154
}
155155

156156
/* Transparent ghost style for secondary action buttons (e.g. "View Usage") */
157-
.chat-input-notification-widget .chat-input-notification-action-button.secondary {
157+
.chat-input-notification-widget .chat-input-notification-action-button.secondary:not(.filled) {
158158
border: none;
159159
background: transparent;
160160
color: var(--vscode-foreground);
@@ -184,7 +184,7 @@
184184
margin: 0;
185185
}
186186

187-
.chat-input-notification-widget .chat-input-notification-action-button.secondary:hover {
187+
.chat-input-notification-widget .chat-input-notification-action-button.secondary:not(.filled):hover {
188188
background: var(--vscode-toolbar-hoverBackground);
189189
opacity: 1;
190190
}

0 commit comments

Comments
 (0)