Skip to content

show copilot instructions prompt at startup #2361

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion vscode/src/createProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export async function initProjectCreator(context: vscode.ExtensionContext) {
}

// Call updateCopilotInstructions to update the Copilot instructions file
await updateCopilotInstructions(folderUri);
await updateCopilotInstructions(folderUri, true);
},
),
);
Expand Down
71 changes: 57 additions & 14 deletions vscode/src/gh-copilot/instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ async function hasQSharpCopilotInstructions(
* Command to update or create the Copilot instructions file for Q#.
* Shows a prompt to the user and updates the file if confirmed.
*/
async function updateGhCopilotInstructionsCommand() {
async function updateGhCopilotInstructionsCommand(userInvoked: boolean) {
const workspaceFolders = vscode.workspace.workspaceFolders;
if (!workspaceFolders || workspaceFolders.length === 0) {
vscode.window.showErrorMessage("No workspace folder is open");
Expand All @@ -191,10 +191,13 @@ async function updateGhCopilotInstructionsCommand() {
resourceUri = currentDoc ?? workspaceFolders[0].uri;
}

return await updateCopilotInstructions(resourceUri);
return await updateCopilotInstructions(resourceUri, userInvoked);
}

export async function updateCopilotInstructions(resource: vscode.Uri) {
export async function updateCopilotInstructions(
resource: vscode.Uri,
userInvoked: boolean,
): Promise<vscode.MessageItem | undefined> {
// Always add copilot instructions in the workspace root
const workspaceFolder = vscode.workspace.getWorkspaceFolder(resource)?.uri;
if (!workspaceFolder) {
Expand All @@ -206,24 +209,46 @@ export async function updateCopilotInstructions(resource: vscode.Uri) {
return;
}

sendTelemetryEvent(EventType.UpdateCopilotInstructionsStart, {}, {});
sendTelemetryEvent(
EventType.UpdateCopilotInstructionsStart,
{
trigger: userInvoked ? "user" : "startup",
},
{},
);

const buttons = [{ title: "Yes" }, { title: "No", isCloseAffordance: true }];
if (!userInvoked) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's user invoked, should we show a confirmation at all, or just update it? It's not like we're doing anything destructive, we only add content. If they explicitly invoked the command, prompting again might be excessive.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe. My goal in showing the prompt was to help the user understand what they just clicked on. They may have been just poking around in the command palette - without this message, there's nothing telling them what actually happened, and I doubt most users would just know about copilot-instructions.md.

buttons.push({ title: "Don't show again" });
}

const modal = userInvoked;

// Show a yes/no prompt to the user
const response = await vscode.window.showInformationMessage(
"We're about to update your `copilot-instructions.md` file.\n\n" +
"This file helps GitHub Copilot understand and work better with Q# files and features provided by the Quantum Development Kit extension.\n\n" +
"Would you like to proceed with updating `copilot-instructions.md`?",
{ modal: true },
{ title: "Yes" },
{ title: "No", isCloseAffordance: true },
"Add Q# guidance to copilot-instructions.md?\n\n" +
"Updating this file will help GitHub Copilot understand and work better with Q# files and other Quantum Development Kit features.\n\n" +
"Learn more at " +
(modal
? "https://aka.ms/qdk.copilot" // links don't render in modal dialogs
: "[https://aka.ms/qdk.copilot](https://aka.ms/qdk.copilot)"),
{
modal,
},
...buttons,
);

if (response?.title !== "Yes") {
sendTelemetryEvent(EventType.UpdateCopilotInstructionsEnd, {
reason: "User canceled",
flowStatus: UserFlowStatus.Aborted,
});
return; // User canceled or dismissed the dialog

vscode.window.showInformationMessage(
"To add Q# guidance to copilot-instructions.md at any time, " +
'run the command "Q#: Update Copilot instructions file for Q#".',
);

return response; // User dismissed the dialog
}

try {
Expand Down Expand Up @@ -274,7 +299,8 @@ export async function updateCopilotInstructions(resource: vscode.Uri) {
{ flowStatus: UserFlowStatus.Failed, reason: "Error" },
{},
);
return;

return response;
}

// Send telemetry event for successful completion
Expand All @@ -292,7 +318,24 @@ export function registerGhCopilotInstructionsCommand(
context.subscriptions.push(
vscode.commands.registerCommand(
"qsharp-vscode.updateCopilotInstructions",
updateGhCopilotInstructionsCommand,
() => updateGhCopilotInstructionsCommand(true),
),
);

// Also do a one-time prompt at startup
if (
context.globalState.get<boolean>(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might want to make this workspaceState since the instructions files are workspace specific

"showUpdateCopilotInstructionsPromptAtStartup",
true,
)
) {
updateGhCopilotInstructionsCommand(false).then((response) => {
if (response?.title === "Don't show again") {
context.globalState.update(
"showUpdateCopilotInstructionsPromptAtStartup",
false,
);
}
});
}
}
4 changes: 3 additions & 1 deletion vscode/src/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,9 @@ type EventTypes = {
};
};
[EventType.UpdateCopilotInstructionsStart]: {
properties: Empty;
properties: {
trigger: "user" | "startup";
};
measurements: Empty;
};
[EventType.UpdateCopilotInstructionsEnd]: {
Expand Down