Skip to content

Commit 30e9257

Browse files
Merge pull request #264 from olasunkanmi-SE/UI-enhancement
feat(ui): Enhance user feedback for CodeBuddy commands
2 parents 92b3ac9 + 0470ed6 commit 30e9257

File tree

5 files changed

+287
-87
lines changed

5 files changed

+287
-87
lines changed

src/commands/handler.ts

Lines changed: 140 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,9 @@ import Anthropic from "@anthropic-ai/sdk";
33
import { GenerativeModel, GoogleGenerativeAI } from "@google/generative-ai";
44
import Groq from "groq-sdk";
55
import * as vscode from "vscode";
6-
import {
7-
APP_CONFIG,
8-
COMMON,
9-
generativeAiModels,
10-
} from "../application/constant";
6+
import { APP_CONFIG, COMMON, generativeAiModels } from "../application/constant";
117
import { AnthropicWebViewProvider } from "../webview-providers/anthropic";
8+
import { DeepseekWebViewProvider } from "../webview-providers/deepseek";
129
import { GeminiWebViewProvider } from "../webview-providers/gemini";
1310
import { GroqWebViewProvider } from "../webview-providers/groq";
1411
import {
@@ -44,7 +41,7 @@ export abstract class CodeCommandHandler implements ICodeCommandHandler {
4441
constructor(
4542
private readonly action: string,
4643
_context: vscode.ExtensionContext,
47-
errorMessage?: string,
44+
errorMessage?: string
4845
) {
4946
this.context = _context;
5047
this.error = errorMessage;
@@ -78,23 +75,132 @@ export abstract class CodeCommandHandler implements ICodeCommandHandler {
7875
return getConfigValue(configKey);
7976
}
8077

81-
protected createModel():
82-
| { generativeAi: string; model: any; modelName: string }
83-
| undefined {
78+
/**
79+
* Get command feedback with action name and description
80+
*/
81+
private getCommandFeedback(action: string): {
82+
action: string;
83+
description: string;
84+
} {
85+
const { CODEBUDDY_ACTIONS } = require("../application/constant");
86+
87+
const commandDescriptions: Record<string, { action: string; description: string }> = {
88+
[CODEBUDDY_ACTIONS.comment]: {
89+
action: "Adding Code Comments",
90+
description:
91+
"CodeBuddy is analyzing your code and adding meaningful comments that explain the intent and logic...",
92+
},
93+
[CODEBUDDY_ACTIONS.review]: {
94+
action: "Reviewing Code Quality",
95+
description:
96+
"CodeBuddy is conducting a comprehensive code review covering security, performance, and best practices...",
97+
},
98+
[CODEBUDDY_ACTIONS.refactor]: {
99+
action: "Refactoring Code",
100+
description: "CodeBuddy is applying SOLID principles and design patterns to improve code maintainability...",
101+
},
102+
[CODEBUDDY_ACTIONS.optimize]: {
103+
action: "Optimizing Performance",
104+
description:
105+
"CodeBuddy is analyzing algorithms and data structures to enhance code performance and efficiency...",
106+
},
107+
[CODEBUDDY_ACTIONS.fix]: {
108+
action: "Fixing Code Issues",
109+
description: "CodeBuddy is diagnosing the error and implementing defensive programming solutions...",
110+
},
111+
[CODEBUDDY_ACTIONS.explain]: {
112+
action: "Explaining Code Logic",
113+
description:
114+
"CodeBuddy is breaking down complex code into clear, educational explanations with real-world context...",
115+
},
116+
[CODEBUDDY_ACTIONS.commitMessage]: {
117+
action: "Generating Commit Message",
118+
description: "CodeBuddy is analyzing your staged changes and crafting a professional commit message...",
119+
},
120+
[CODEBUDDY_ACTIONS.interviewMe]: {
121+
action: "Preparing Interview Questions",
122+
description: "CodeBuddy is creating comprehensive technical interview questions based on your code...",
123+
},
124+
[CODEBUDDY_ACTIONS.generateUnitTest]: {
125+
action: "Generating Unit Tests",
126+
description: "CodeBuddy is creating comprehensive test suites with edge cases and mocking strategies...",
127+
},
128+
[CODEBUDDY_ACTIONS.generateDiagram]: {
129+
action: "Creating System Diagram",
130+
description: "CodeBuddy is visualizing your code architecture with professional Mermaid diagrams...",
131+
},
132+
[CODEBUDDY_ACTIONS.reviewPR]: {
133+
action: "Reviewing Pull Request",
134+
description:
135+
"CodeBuddy is conducting a thorough PR review with security, performance, and architecture analysis...",
136+
},
137+
[CODEBUDDY_ACTIONS.inlineChat]: {
138+
action: "Processing Inline Request",
139+
description: "CodeBuddy is analyzing your inline query and generating a contextual response...",
140+
},
141+
};
142+
143+
return (
144+
commandDescriptions[action] || {
145+
action: "Processing Request",
146+
description: "CodeBuddy is analyzing your code and generating a response...",
147+
}
148+
);
149+
}
150+
151+
/**
152+
* Send command feedback to the webview
153+
*/
154+
private async sendCommandFeedback(action: string): Promise<void> {
155+
const feedback = this.getCommandFeedback(action);
156+
157+
switch (this.generativeAi) {
158+
case generativeAiModels.GROQ:
159+
await GroqWebViewProvider.webView?.webview.postMessage({
160+
type: "codebuddy-commands",
161+
message: feedback,
162+
});
163+
break;
164+
case generativeAiModels.GEMINI:
165+
await GeminiWebViewProvider.webView?.webview.postMessage({
166+
type: "codebuddy-commands",
167+
message: feedback,
168+
});
169+
break;
170+
case generativeAiModels.DEEPSEEK:
171+
await DeepseekWebViewProvider.webView?.webview.postMessage({
172+
type: "codebuddy-commands",
173+
message: feedback,
174+
});
175+
break;
176+
case generativeAiModels.ANTHROPIC:
177+
case generativeAiModels.GROK:
178+
await AnthropicWebViewProvider.webView?.webview.postMessage({
179+
type: "codebuddy-commands",
180+
message: feedback,
181+
});
182+
break;
183+
default:
184+
this.logger.error("Unknown generative AI", "");
185+
break;
186+
}
187+
}
188+
189+
protected createModel(): { generativeAi: string; model: any; modelName: string } | undefined {
84190
try {
85191
let model;
86192
let modelName = "";
87193
if (!this.generativeAi) {
88194
vscodeErrorMessage(
89-
"Configuration not found. Go to settings, search for Your coding buddy. Fill up the model and model name",
195+
"Configuration not found. Go to settings, search for Your coding buddy. Fill up the model and model name"
90196
);
91197
}
92198
if (this.generativeAi === generativeAiModels.GROQ) {
93199
const apiKey = this.groqApiKey;
94200
modelName = this.groqModel;
95201
if (!apiKey || !modelName) {
96202
vscodeErrorMessage(
97-
"Configuration not found. Go to settings, search for Your coding buddy. Fill up the model and model name",
203+
"Configuration not found. Go to settings, search for Your coding buddy. Fill up the model and model name"
98204
);
99205
}
100206
model = this.createGroqModel(apiKey);
@@ -120,9 +226,7 @@ export abstract class CodeCommandHandler implements ICodeCommandHandler {
120226
return { generativeAi: this.generativeAi, model, modelName };
121227
} catch (error) {
122228
console.error("Error creating model:", error);
123-
vscode.window.showErrorMessage(
124-
"An error occurred while creating the model. Please try again.",
125-
);
229+
vscode.window.showErrorMessage("An error occurred while creating the model. Please try again.");
126230
}
127231
}
128232

@@ -155,9 +259,7 @@ export abstract class CodeCommandHandler implements ICodeCommandHandler {
155259
return new Groq({ apiKey });
156260
}
157261

158-
protected async generateModelResponse(
159-
text: string,
160-
): Promise<string | Anthropic.Messages.Message | undefined> {
262+
protected async generateModelResponse(text: string): Promise<string | Anthropic.Messages.Message | undefined> {
161263
try {
162264
if (text?.length > 0) {
163265
this.orchestrator.publish("onUserPrompt", text);
@@ -197,7 +299,7 @@ export abstract class CodeCommandHandler implements ICodeCommandHandler {
197299

198300
if (!response) {
199301
throw new Error(
200-
"Could not generate response. Check your settings, ensure the API keys and Model Name is added properly.",
302+
"Could not generate response. Check your settings, ensure the API keys and Model Name is added properly."
201303
);
202304
}
203305
if (this.action.includes("chart")) {
@@ -208,9 +310,7 @@ export abstract class CodeCommandHandler implements ICodeCommandHandler {
208310
return response;
209311
} catch (error) {
210312
this.logger.error("Error generating response:", error);
211-
vscode.window.showErrorMessage(
212-
"An error occurred while generating the response. Please try again.",
213-
);
313+
vscode.window.showErrorMessage("An error occurred while generating the response. Please try again.");
214314
}
215315
}
216316

@@ -221,18 +321,15 @@ export abstract class CodeCommandHandler implements ICodeCommandHandler {
221321
return inputString;
222322
}
223323

224-
async generateGeminiResponse(
225-
model: any,
226-
text: string,
227-
): Promise<string | undefined> {
324+
async generateGeminiResponse(model: any, text: string): Promise<string | undefined> {
228325
const result = await model.generateContent(text);
229326
return result ? await result.response.text() : undefined;
230327
}
231328

232329
private async anthropicResponse(
233330
model: Anthropic,
234331
generativeAiModel: string,
235-
userPrompt: string,
332+
userPrompt: string
236333
): Promise<string | undefined> {
237334
try {
238335
const response = await model.messages.create({
@@ -256,15 +353,9 @@ export abstract class CodeCommandHandler implements ICodeCommandHandler {
256353
}
257354
}
258355

259-
private async groqResponse(
260-
model: Groq,
261-
prompt: string,
262-
generativeAiModel: string,
263-
): Promise<string | undefined> {
356+
private async groqResponse(model: Groq, prompt: string, generativeAiModel: string): Promise<string | undefined> {
264357
try {
265-
const chatHistory = Memory.has(COMMON.ANTHROPIC_CHAT_HISTORY)
266-
? Memory.get(COMMON.GROQ_CHAT_HISTORY)
267-
: [];
358+
const chatHistory = Memory.has(COMMON.ANTHROPIC_CHAT_HISTORY) ? Memory.get(COMMON.GROQ_CHAT_HISTORY) : [];
268359
const params = {
269360
messages: [
270361
...chatHistory,
@@ -276,8 +367,7 @@ export abstract class CodeCommandHandler implements ICodeCommandHandler {
276367
model: generativeAiModel,
277368
};
278369

279-
const completion: Groq.Chat.ChatCompletion =
280-
await model.chat.completions.create(params);
370+
const completion: Groq.Chat.ChatCompletion = await model.chat.completions.create(params);
281371
return completion.choices[0]?.message?.content ?? undefined;
282372
} catch (error) {
283373
this.logger.error("Error generating response:", error);
@@ -288,9 +378,7 @@ export abstract class CodeCommandHandler implements ICodeCommandHandler {
288378

289379
abstract createPrompt(text?: string): any;
290380

291-
async generateResponse(
292-
message?: string,
293-
): Promise<string | Anthropic.Messages.Message | undefined> {
381+
async generateResponse(message?: string): Promise<string | Anthropic.Messages.Message | undefined> {
294382
this.logger.info(this.action);
295383
let prompt;
296384
const selectedCode = this.getSelectedWindowArea();
@@ -302,9 +390,7 @@ export abstract class CodeCommandHandler implements ICodeCommandHandler {
302390
if (message && selectedCode) {
303391
prompt = await this.createPrompt(`${message} \n ${selectedCode}`);
304392
} else {
305-
message
306-
? (prompt = await this.createPrompt(message))
307-
: (prompt = await this.createPrompt(selectedCode));
393+
message ? (prompt = await this.createPrompt(message)) : (prompt = await this.createPrompt(selectedCode));
308394
}
309395

310396
if (!prompt) {
@@ -387,9 +473,7 @@ export abstract class CodeCommandHandler implements ICodeCommandHandler {
387473
placeHolder: "Enter instructions for CodeBuddy",
388474
ignoreFocusOut: true,
389475
validateInput: (text) => {
390-
return text === ""
391-
? "Enter instructions for CodeBuddy or press Escape to close chat box"
392-
: null;
476+
return text === "" ? "Enter instructions for CodeBuddy or press Escape to close chat box" : null;
393477
},
394478
});
395479
return userPrompt;
@@ -400,10 +484,11 @@ export abstract class CodeCommandHandler implements ICodeCommandHandler {
400484

401485
async execute(action?: string, message?: string): Promise<void> {
402486
try {
487+
// Send command feedback immediately at the start
488+
await this.sendCommandFeedback(action || this.action);
489+
403490
let prompt: string | undefined;
404-
const response = (await this.generateResponse(
405-
prompt ?? message,
406-
)) as string;
491+
const response = (await this.generateResponse(prompt ?? message)) as string;
407492
if (!response) {
408493
vscode.window.showErrorMessage("model not reponding, try again later");
409494
return;
@@ -426,12 +511,14 @@ export abstract class CodeCommandHandler implements ICodeCommandHandler {
426511
message: formattedResponse,
427512
});
428513
break;
514+
case generativeAiModels.DEEPSEEK:
515+
await DeepseekWebViewProvider.webView?.webview.postMessage({
516+
type: "bot-response",
517+
message: formattedResponse,
518+
});
519+
break;
429520
case generativeAiModels.ANTHROPIC:
430521
case generativeAiModels.GROK:
431-
await AnthropicWebViewProvider.webView?.webview.postMessage({
432-
type: "codebuddy-commands",
433-
message: action,
434-
});
435522
await AnthropicWebViewProvider.webView?.webview.postMessage({
436523
type: "bot-response",
437524
message: formattedResponse,
@@ -442,10 +529,7 @@ export abstract class CodeCommandHandler implements ICodeCommandHandler {
442529
break;
443530
}
444531
} catch (error) {
445-
this.logger.error(
446-
"Error while passing model response to the webview",
447-
error,
448-
);
532+
this.logger.error("Error while passing model response to the webview", error);
449533
}
450534
}
451535
}

0 commit comments

Comments
 (0)