Skip to content
This repository was archived by the owner on Jun 28, 2026. It is now read-only.

Commit 1af6295

Browse files
Merge pull request #115 from olasunkanmi-SE/inline-chat
feat(api, ui): Add in-line chat functionality
2 parents c24b9cc + d6423c1 commit 1af6295

8 files changed

Lines changed: 112 additions & 38 deletions

File tree

package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@
8282
"command": "CodeBuddy.generateCommitMessage",
8383
"group": "CodeBuddy"
8484
},
85+
{
86+
"command": "CodeBuddy.inLineChat",
87+
"group":"CodeBuddy"
88+
},
8589
{
8690
"when": "editorHasSelection",
8791
"command": "CodeBuddy.interviewMe",
@@ -136,6 +140,10 @@
136140
"command": "CodeBuddy.generateCommitMessage",
137141
"title": "CodeBuddy. Generate commit message"
138142
},
143+
{
144+
"command": "CodeBuddy.inLineChat",
145+
"title": "CodeBuddy. Inline chat"
146+
},
139147
{
140148
"command": "CodeBuddy.interviewMe",
141149
"title": "CodeBuddy. Interview Me."

src/constant.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export enum OLA_ACTIONS {
1212
interviewMe = "CodeBuddy.interviewMe",
1313
generateUnitTest = "CodeBuddy.generateUnitTest",
1414
generateCodeChart = "CodeBuddy.generateCodeChart",
15+
inlineChat = "CodeBuddy.inLineChat",
1516
}
1617

1718
export enum COMMON {

src/events/event-generator.ts

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -278,19 +278,23 @@ export abstract class EventGenerator implements IEventGenerator {
278278
abstract createPrompt(text?: string): any;
279279

280280
async generateResponse(
281-
errorMessage?: string,
281+
message?: string,
282282
): Promise<string | Anthropic.Messages.Message | undefined> {
283283
this.showInformationMessage();
284284
let prompt;
285285
const selectedCode = this.getSelectedWindowArea();
286-
if (!errorMessage && !selectedCode) {
286+
if (!message && !selectedCode) {
287287
vscode.window.showErrorMessage("select a piece of code.");
288288
return;
289289
}
290290

291-
errorMessage
292-
? (prompt = await this.createPrompt(errorMessage))
293-
: (prompt = await this.createPrompt(selectedCode));
291+
if (message && selectedCode) {
292+
prompt = await this.createPrompt(`${message} \n ${selectedCode}`);
293+
} else {
294+
message
295+
? (prompt = await this.createPrompt(message))
296+
: (prompt = await this.createPrompt(selectedCode));
297+
}
294298

295299
if (!prompt) {
296300
vscode.window.showErrorMessage("model not reponding, try again later");
@@ -366,8 +370,37 @@ export abstract class EventGenerator implements IEventGenerator {
366370
return response;
367371
}
368372

369-
async execute(errorMessage?: string): Promise<void> {
370-
const response = (await this.generateResponse(errorMessage)) as string;
373+
async getUserInLineChat(): Promise<string | undefined> {
374+
try {
375+
const userPrompt = await vscode.window.showInputBox({
376+
placeHolder: "Enter instructions for CodeBuddy",
377+
ignoreFocusOut: true,
378+
validateInput: (text) => {
379+
return text === ""
380+
? "Enter instructions for CodeBuddy or press Escape to close chat box"
381+
: null;
382+
},
383+
});
384+
if (userPrompt) {
385+
Brain.set("inLineChat", true);
386+
}
387+
return userPrompt;
388+
} catch (error) {
389+
vscode.window.showInformationMessage(
390+
`Error occured while getting user prompt`,
391+
);
392+
console.log(error);
393+
}
394+
}
395+
396+
async execute(message?: string): Promise<void> {
397+
const prompt: string | undefined = await this.getUserInLineChat();
398+
if (prompt && Brain.has("inLineChat")) {
399+
Brain.delete("inLineChat");
400+
}
401+
const response = (await this.generateResponse(
402+
prompt ? prompt : message,
403+
)) as string;
371404
if (!response) {
372405
vscode.window.showErrorMessage("model not reponding, try again later");
373406
return;

src/events/inline-chat.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { formatText } from "../utils";
2+
import { EventGenerator } from "./event-generator";
3+
import * as vscode from "vscode";
4+
5+
export class InLineChat extends EventGenerator {
6+
selectedCode: string | undefined;
7+
constructor(action: string, context: vscode.ExtensionContext) {
8+
super(action, context);
9+
}
10+
11+
getCurrentActiveEditorCode(): string | undefined {
12+
const editor = vscode.window.activeTextEditor;
13+
return editor ? editor?.document?.getText() : undefined;
14+
}
15+
16+
formatResponse(comment: string): string {
17+
return formatText(comment);
18+
}
19+
20+
createPrompt(selectedCode: string): string {
21+
let context = this.getCurrentActiveEditorCode() ?? "";
22+
const fullPrompt = `${selectedCode} \n Here is the code context ${context}`;
23+
return fullPrompt;
24+
}
25+
}

src/extension.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { setUpGenerativeAiModel } from "./services/generative-ai-model-manager";
2525
import { getConfigValue } from "./utils";
2626
import { AnthropicWebViewProvider } from "./providers/anthropic-web-view-provider";
2727
import { Brain } from "./services/memory";
28+
import { InLineChat } from "./events/inline-chat";
2829

2930
const {
3031
geminiKey,
@@ -53,11 +54,16 @@ export async function activate(context: vscode.ExtensionContext) {
5354
interviewMe,
5455
generateUnitTest,
5556
generateCodeChart,
57+
inlineChat,
5658
} = OLA_ACTIONS;
5759
const getComment = new Comments(
5860
`${USER_MESSAGE} generates the code comments...`,
5961
context,
6062
);
63+
const getInLineChat = new InLineChat(
64+
`${USER_MESSAGE} generates a response...`,
65+
context,
66+
);
6167
const generateOptimizeCode = new OptimizeCode(
6268
`${USER_MESSAGE} optimizes the code...`,
6369
context,
@@ -115,6 +121,7 @@ export async function activate(context: vscode.ExtensionContext) {
115121
[knowledge]: () => knowledgeBase.execute(),
116122
[commitMessage]: () => generateCommitMessage.execute("hello"),
117123
[generateCodeChart]: () => codeChartGenerator.execute(),
124+
[inlineChat]: () => getInLineChat.execute(),
118125
};
119126

120127
const subscriptions: vscode.Disposable[] = Object.entries(actionMap).map(

src/providers/code-actions-provider.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export class CodeActionsProvider implements vscode.CodeActionProvider {
55
document: vscode.TextDocument,
66
range: vscode.Range,
77
context: vscode.CodeActionContext,
8-
token: vscode.CancellationToken
8+
token: vscode.CancellationToken,
99
): vscode.ProviderResult<(vscode.Command | vscode.CodeAction)[]> {
1010
return this.quickFix(context, document);
1111
}
@@ -18,11 +18,11 @@ export class CodeActionsProvider implements vscode.CodeActionProvider {
1818
// This returns the whole line where the error occured
1919
const erroredLineOfCode = this.getErroredFunction(
2020
document,
21-
diagnostic.range
21+
diagnostic.range,
2222
);
2323
const action = new vscode.CodeAction(
2424
"CodeBuddy fix this error",
25-
vscode.CodeActionKind.QuickFix
25+
vscode.CodeActionKind.QuickFix,
2626
);
2727
const windowContent = document.getText();
2828
// Seems the text is too much `${errorMessage} \n ${windowContent}`
@@ -39,13 +39,13 @@ export class CodeActionsProvider implements vscode.CodeActionProvider {
3939

4040
private getErroredFunction(
4141
document: vscode.TextDocument,
42-
range: vscode.Range
42+
range: vscode.Range,
4343
): string {
4444
const startLine = range.start.line;
4545
const endLine = range.end.line;
4646
const erroredFunctionRange: vscode.Range = new vscode.Range(
4747
new vscode.Position(startLine, 0),
48-
new vscode.Position(endLine + 1, 0)
48+
new vscode.Position(endLine + 1, 0),
4949
);
5050
return document.getText(erroredFunctionRange);
5151
}

src/providers/groq-web-view-provider.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ export class GroqWebViewProvider extends BaseWebViewProvider {
1616
extensionUri: vscode.Uri,
1717
apiKey: string,
1818
generativeAiModel: string,
19-
context: vscode.ExtensionContext
19+
context: vscode.ExtensionContext,
2020
) {
2121
super(extensionUri, apiKey, generativeAiModel, context);
2222
}
2323

2424
public async sendResponse(
2525
response: string,
26-
currentChat: string
26+
currentChat: string,
2727
): Promise<boolean | undefined> {
2828
try {
2929
const type = currentChat === "bot" ? "bot-response" : "user-input";
@@ -60,7 +60,7 @@ export class GroqWebViewProvider extends BaseWebViewProvider {
6060
async generateResponse(
6161
apiKey = undefined,
6262
name = undefined,
63-
message: string
63+
message: string,
6464
): Promise<string | undefined> {
6565
try {
6666
const { temperature, max_tokens, top_p, stop } = GROQ_CONFIG;
@@ -99,7 +99,7 @@ export class GroqWebViewProvider extends BaseWebViewProvider {
9999
console.error(error);
100100
Brain.set(COMMON.GROQ_CHAT_HISTORY, []);
101101
vscode.window.showErrorMessage(
102-
"Model not responding, please resend your question"
102+
"Model not responding, please resend your question",
103103
);
104104
return;
105105
}

src/services/chat-manager.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,10 @@ export class ChatManager {
7373
} catch (error) {
7474
console.error(error);
7575
vscodeErrorMessage(
76-
"Failed to generate content. Please try again later."
76+
"Failed to generate content. Please try again later.",
7777
);
7878
}
79-
}
79+
},
8080
);
8181
}
8282

@@ -132,60 +132,60 @@ export class ChatManager {
132132
const generativeAi: string | undefined = getGenerativeAiModel();
133133
if (generativeAi === generativeAiModels.GROQ) {
134134
const groqAiConfigurations = this.handleAiProvider(
135-
generativeAiModels.GROQ
135+
generativeAiModels.GROQ,
136136
);
137137
const chatViewProvider = new GroqWebViewProvider(
138138
this._context.extensionUri,
139139
groqAiConfigurations.apiKey,
140140
groqAiConfigurations.model,
141-
this._context
141+
this._context,
142142
);
143143
return await chatViewProvider.generateResponse(
144144
undefined,
145145
undefined,
146-
message
146+
message,
147147
);
148148
}
149149
if (generativeAi === generativeAiModels.GEMINI) {
150150
const geminiConfigurations = this.handleAiProvider(
151-
generativeAiModels.GEMINI
151+
generativeAiModels.GEMINI,
152152
);
153153
const geminiWebViewProvider = new GeminiWebViewProvider(
154154
this._context.extensionUri,
155155
geminiConfigurations.apiKey,
156156
geminiConfigurations.model,
157-
this._context
157+
this._context,
158158
);
159159
return await geminiWebViewProvider.generateResponse(
160160
geminiConfigurations.apiKey,
161161
geminiConfigurations.model,
162-
message
162+
message,
163163
);
164164
}
165165
if (generativeAi === "Anthropic") {
166166
const anthropicConfigurations: aIProviderConfig = this.handleAiProvider(
167-
generativeAiModels.ANTHROPIC
167+
generativeAiModels.ANTHROPIC,
168168
);
169169
const anthropicWebViewProvider = this.getAnthropicWebViewProvider(
170-
anthropicConfigurations
170+
anthropicConfigurations,
171171
);
172172
return await anthropicWebViewProvider.generateResponse(
173173
undefined,
174174
undefined,
175-
message
175+
message,
176176
);
177177
}
178178

179179
if (generativeAi === generativeAiModels.GROK) {
180180
const grokConfigurations: aIProviderConfig = this.handleAiProvider(
181-
generativeAiModels.GROK
181+
generativeAiModels.GROK,
182182
);
183183
const anthropicWebViewProvider =
184184
this.getAnthropicWebViewProvider(grokConfigurations);
185185
return await anthropicWebViewProvider.generateResponse(
186186
undefined,
187187
undefined,
188-
message
188+
message,
189189
);
190190
}
191191
} catch (error) {
@@ -202,7 +202,7 @@ export class ChatManager {
202202
this._context.extensionUri,
203203
this.groqApiKey,
204204
this.groqModel,
205-
this._context
205+
this._context,
206206
);
207207
chatViewProvider.sendResponse(formatText(userInput), COMMON.USER_INPUT);
208208
chatViewProvider.sendResponse(formatText(response), COMMON.BOT);
@@ -212,11 +212,11 @@ export class ChatManager {
212212
this._context.extensionUri,
213213
this.geminiApiKey,
214214
this.geminiModel,
215-
this._context
215+
this._context,
216216
);
217217
geminiWebViewProvider.sendResponse(
218218
formatText(userInput),
219-
COMMON.USER_INPUT
219+
COMMON.USER_INPUT,
220220
);
221221
geminiWebViewProvider.sendResponse(formatText(response), COMMON.BOT);
222222
}
@@ -227,24 +227,24 @@ export class ChatManager {
227227
let anthropicConfigurations: aIProviderConfig | undefined;
228228
if (this.generativeAi === generativeAiModels.ANTHROPIC) {
229229
anthropicConfigurations = this.handleAiProvider(
230-
generativeAiModels.ANTHROPIC
230+
generativeAiModels.ANTHROPIC,
231231
);
232232
}
233233
if (this.generativeAi === generativeAiModels.GROK) {
234234
anthropicConfigurations = this.handleAiProvider(
235-
generativeAiModels.GROK
235+
generativeAiModels.GROK,
236236
);
237237
}
238238
if (!anthropicConfigurations) {
239239
throw new Error(`Configuration not found for ${this.generativeAi}`);
240240
}
241241

242242
const anthropicWebViewProvider = this.getAnthropicWebViewProvider(
243-
anthropicConfigurations
243+
anthropicConfigurations,
244244
);
245245
anthropicWebViewProvider.sendResponse(
246246
formatText(userInput),
247-
COMMON.USER_INPUT
247+
COMMON.USER_INPUT,
248248
);
249249
anthropicWebViewProvider.sendResponse(formatText(response), COMMON.BOT);
250250
}
@@ -256,7 +256,7 @@ export class ChatManager {
256256
}
257257

258258
private getAnthropicWebViewProvider(
259-
config: aIProviderConfig
259+
config: aIProviderConfig,
260260
): AnthropicWebViewProvider {
261261
let xGrokBaseURL;
262262
if (getConfigValue(APP_CONFIG.generativeAi) === generativeAiModels.GROK) {
@@ -267,7 +267,7 @@ export class ChatManager {
267267
config.apiKey,
268268
config.model,
269269
this._context,
270-
xGrokBaseURL
270+
xGrokBaseURL,
271271
);
272272
}
273273
}

0 commit comments

Comments
 (0)