Skip to content
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
4 changes: 4 additions & 0 deletions GETTING_STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,7 @@ If the extension is installed and enabled, but not able to select a model, make
General feedback can be provided to the Qiskit Code Assistant team by clicking on the `Provide feedback` icon in status bar (left of the Qiskit Code Assistant model info).

Feedback for a specific prompt and generated code suggestion can be provided by clicking on the `thumbs up`/`thumbs down` icons that appear immediately above the suggested code block.

### Code Migration Feedback

After using the code migration feature (sparkle icon ✨), feedback can be provided in the same way as code suggestions - through the `thumbs up`/`thumbs down` icons that appear above the migrated code block.
8 changes: 8 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@
"title": "Qiskit Code Assistant: Migrate code",
"icon": "$(sparkle)",
"enablement": "qiskit-vscode.model-selected"
},
{
"command": "qiskit-vscode.migration-feedback",
"title": "Qiskit Code Assistant: Provide migration feedback"
},
{
"command": "qiskit-vscode.debug-streaming",
"title": "Qiskit Code Assistant: Debug streaming configuration"
}
],
"configuration": {
Expand Down
71 changes: 71 additions & 0 deletions src/commands/debugStreaming.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import vscode from "vscode";

/**
* Command to test and debug streaming configuration
*/
async function handler(): Promise<void> {
console.log("=== Qiskit Code Assistant Streaming Debug ===");

// Get current configuration
const config = vscode.workspace.getConfiguration("qiskitCodeAssistant");
const streamingEnabled = config.get<boolean>("enableStreaming");
const telemetryEnabled = config.get<boolean>("enableTelemetry");

console.log("Current configuration:", {
streamingEnabled,
telemetryEnabled,
configSource: config.inspect("enableStreaming")
});

// Test streaming endpoint (if possible)
try {
const testResult = await testStreamingEndpoint();
console.log("Streaming test result:", testResult);
} catch (error) {
console.error("Streaming test failed:", error);
}

// Show result to user
const message = `Streaming Debug Results:
- Streaming Enabled: ${streamingEnabled}
- Telemetry Enabled: ${telemetryEnabled}
- Check console for detailed logs`;

vscode.window.showInformationMessage(
message,
"Open Console",
"Toggle Streaming",
"Dismiss"
).then((choice) => {
if (choice === "Open Console") {
vscode.commands.executeCommand("workbench.action.toggleDevTools");
} else if (choice === "Toggle Streaming") {
config.update("enableStreaming", !streamingEnabled, vscode.ConfigurationTarget.Global);
vscode.window.showInformationMessage(`Streaming ${!streamingEnabled ? 'enabled' : 'disabled'}`);
}
});
}

async function testStreamingEndpoint(): Promise<any> {
const testStream = async function* () {
yield { test: "chunk1", generated_text: "hello " };
yield { test: "chunk2", generated_text: "world!" };
};

const chunks: any[] = [];
for await (const chunk of testStream()) {
chunks.push(chunk);
}

return {
chunksReceived: chunks.length,
chunks: chunks
};
}

const command: CommandModule = {
identifier: "qiskit-vscode.debug-streaming",
handler,
};

export default command;
4 changes: 4 additions & 0 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@ import { handleChangeModelStatusBar, handleProvideFeedbackStatusBar } from "./ha
import { handleProvideFeedback, handleClearCodelens} from "./handleFeedback";
import setApiToken from "./setApiToken";
import migrateQiskitCode from "./migrateQiskitCode";
import migrationFeedback from "./migrationFeedback";
import debugStreaming from "./debugStreaming";

const commands: CommandModule[] = [
acceptDisclaimer,
acceptSuggestionCommand,
debugStreaming,
dismissSuggestionCommand,
handleChangeModelStatusBar,
handleClearCodelens,
handleGetCompletion,
migrateQiskitCode,
migrationFeedback,
handleProvideFeedbackStatusBar,
handleProvideFeedback,
selectModel,
Expand Down
141 changes: 77 additions & 64 deletions src/commands/migrateQiskitCode.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,52 @@
import vscode from "vscode";
import { migrateCode } from "../services/qiskitMigration";
import { migrateCode, MigrationResult } from "../services/qiskitMigration";
import { setDefaultStatus, setLoadingStatus } from "../statusBar/statusBar";
import { currentModel } from "./selectModel";
import { getServiceApi } from "../services/common";
import { addPromptFeedbackCodeLens } from "../codelens/FeedbackCodelensProvider";

let isRunning = false;

function migrationCompletionMsg(outputText: string, isFullDoc: boolean) {
if (!outputText) {
return isFullDoc ? "No code was found in the document that needed to be migrated" : "No code was found in the selected lines that needed to be migrataed"
async function showMigrationFeedback(migrationResult: MigrationResult, migrationStartPosition: vscode.Position): Promise<void> {
console.log("showMigrationFeedback called with:", {
hasCurrentModel: !!currentModel,
migrationId: migrationResult.migrationId,
hasOriginalCode: !!migrationResult.originalCode,
hasMigratedCode: !!migrationResult.migratedCode
});

if (!currentModel) {
console.log("No current model selected, skipping feedback");
return; // Can't provide feedback without model
}

const serviceApi = await getServiceApi();
console.log("Service API feedback enabled:", serviceApi.enableFeedback);

if (!serviceApi.enableFeedback) {
console.log("Feedback not enabled for this service, skipping feedback");
return; // Feedback not enabled for this service
}

// Use the same CodeLens feedback system as normal completions
console.log("Adding migration feedback CodeLens");

// Add CodeLens with thumbs up/down icons above the migrated code
await addPromptFeedbackCodeLens(
currentModel!._id,
migrationResult.migrationId, // Use migration_id as prompt_id equivalent
migrationStartPosition, // Position where the migration started
migrationResult.originalCode, // input
migrationResult.migratedCode // output
);

// Trigger CodeLens refresh to show the feedback icons
vscode.commands.executeCommand('vscode.executeCodeLensProvider');
}

function migrationCompletionMsg(migrationResult: MigrationResult | null, isFullDoc: boolean) {
if (!migrationResult || !migrationResult.migratedCode) {
return isFullDoc ? "No code was found in the document that needed to be migrated" : "No code was found in the selected lines that needed to be migrated"
} else {
return isFullDoc ? "Document successfully migrated" : "Selected code successfully migrated";
}
Expand All @@ -21,7 +61,7 @@ async function handler(): Promise<void> {
}

isRunning = true;
setLoadingStatus();
setLoadingStatus('connecting');

const selection = editor.selection;
let firstLine: vscode.TextLine;
Expand Down Expand Up @@ -51,74 +91,47 @@ async function handler(): Promise<void> {
}

try {
const notificationTitle = `Migrating the ${selection.isEmpty ? "document" : "selected"} code`;

let end = lastLine.range.end;
let migratedText = await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
cancellable: false,
title: notificationTitle
}, async (progress):Promise<string> => {
setLoadingStatus('connecting');

const migrationResult = await (async (): Promise<MigrationResult | null> => {
setLoadingStatus('generating');

progress.report({ increment: 10, message: "Please wait..." });

let t = ""
let responseData = migrateCode(text);
let step = 0;
for await (let chunk of responseData) {
if ((chunk as unknown as {error: string})?.error) {
throw Error((chunk as unknown as {error: string})?.error)
}

// update notidication message based on streaming data progress
if (chunk.plan_steps && step < 1) {
progress.report({ message: "Planning migration...", increment: 25 });
step = 1;
}
if (chunk.final_thoughts && step < 2) {
progress.report({ message: "Reviewing migration...", increment: 25 });
step = 2;
}
if (chunk.migrated_code && step < 3) {
progress.report({ message: "Returning response...", increment: 25 });
step = 3;
}

if (step == 3) {
t += chunk.migrated_code

// calculate the new text range for the additional
// streaming data to be inserted into document
const migratedLines = t.split("\n");
const newLastLine = firstLine.lineNumber + migratedLines.length - 1;
const lastChar = migratedLines[migratedLines.length - 1].length + 1;
const lastPosition = new vscode.Position(newLastLine, lastChar);
const textRange = new vscode.Range(firstLine.range.start, end);

end = lastPosition;

editor.edit(editBuilder => {
editBuilder.replace(textRange, t);
});
}
}
let result = await migrateCode(text);

progress.report({ increment: 100 });
return t;
});
setLoadingStatus('processing');

if (text.trim() == migratedText.trim()) {
migratedText = ""
}
if (text.trim() === result.migratedCode.trim()) {
return null;

}

const infoMsg = migrationCompletionMsg(migratedText, fullDocMigration)
if (!migratedText) {
return result;
})();

const infoMsg = migrationCompletionMsg(migrationResult, fullDocMigration)
if (!migrationResult || !migrationResult.migratedCode) {
vscode.window.showInformationMessage(infoMsg);
return;
}

editor.selection = new vscode.Selection(firstLine.range.start, end);
editor.edit(editBuilder => {
editBuilder.replace(textRange, migrationResult.migratedCode);
});
const migratedLines = migrationResult.migratedCode.split("\n");
const newLastLine = firstLine.lineNumber + migratedLines.length - 1;
const lastChar = migratedLines[migratedLines.length - 1].length + 1;
const lastPosition = new vscode.Position(newLastLine, lastChar);

editor.selection = new vscode.Selection(firstLine.range.start, lastPosition);
vscode.window.showInformationMessage(infoMsg);

// Show feedback options after successful migration
try {
await showMigrationFeedback(migrationResult, firstLine.range.start);
} catch (feedbackError) {
console.error("Error showing migration feedback:", feedbackError);
// Don't throw the error, just log it so migration success isn't affected
}
} catch(error) {
throw error;
} finally {
Expand Down
51 changes: 51 additions & 0 deletions src/commands/migrationFeedback.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import vscode from "vscode";
import { currentModel } from "./selectModel";
import { getServiceApi } from "../services/common";

async function migrationFeedbackHandler(): Promise<void> {
console.log("qiskit-vscode.migration-feedback::handler");

if (!currentModel) {
vscode.window.showErrorMessage("Please select a model before providing migration feedback.");
return;
}

const serviceApi = await getServiceApi();
if (!serviceApi.enableFeedback) {
vscode.window.showInformationMessage("Feedback is not enabled for this service.");
return;
}

// Ask for general migration feedback when user manually triggers it
const comment = await vscode.window.showInputBox({
prompt: "Share your feedback about the Qiskit Code Assistant migration feature:",
placeHolder: "Your feedback helps improve the migration service..."
});

if (!comment) {
return; // User cancelled
}

try {
await serviceApi.postFeedback(
currentModel._id,
undefined, // No specific migration ID for general feedback
undefined, // No positive/negative classification for general feedback
comment,
undefined, // No specific input
undefined // No specific output
);

vscode.window.showInformationMessage("Thank you for your feedback about the migration feature!");
} catch (error) {
console.error("Failed to submit migration feedback:", error);
vscode.window.showErrorMessage("Failed to submit feedback. Please try again later.");
}
}

const command: CommandModule = {
identifier: "qiskit-vscode.migration-feedback",
handler: migrationFeedbackHandler,
};

export default command;
6 changes: 5 additions & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,25 @@ export async function activate(

if (context.extensionMode !== vscode.ExtensionMode.Test) {
handlePluginInstalled(context);

}

return Promise.resolve();
}

async function backgroundInit(context: vscode.ExtensionContext) {

commands.forEach((command) =>
commands.forEach((command) => {
context.subscriptions.push(
vscode.commands.registerCommand(command.identifier, command.handler)
)
}
);

await initApiToken(context);

await initModels(context);

await installAutocomplete(context);
}

Expand Down
Loading