Skip to content

Commit

Permalink
Improve type safety and reusability in BaseEmitter
Browse files Browse the repository at this point in the history
Introduce LocalStorageManager for secure data storage
  • Loading branch information
Olasunkanmi Oyinlola authored and Olasunkanmi Oyinlola committed Jan 28, 2025
1 parent 2ae80e4 commit 0084bef
Show file tree
Hide file tree
Showing 12 changed files with 321 additions and 84 deletions.
2 changes: 1 addition & 1 deletion src/agents/orchestrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class Orchestrator implements vscode.Disposable {

constructor(private readonly aiAgent: BaseAiAgent) {
this.disposables.push(
this.aiAgent.onStatus(this.handleStatus.bind(this)),
this.aiAgent.onStatusChange(this.handleStatus.bind(this)),
this.aiAgent.onError(this.handleError.bind(this)),
);
}
Expand Down
82 changes: 61 additions & 21 deletions src/commands/event-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import Anthropic from "@anthropic-ai/sdk";
import { GenerativeModel, GoogleGenerativeAI } from "@google/generative-ai";
import Groq from "groq-sdk";
import * as vscode from "vscode";
import { APP_CONFIG, COMMON, generativeAiModels } from "../application/constant";
import {
APP_CONFIG,
COMMON,
generativeAiModels,
} from "../application/constant";
import { AnthropicWebViewProvider } from "../providers/anthropic";
import { GeminiWebViewProvider } from "../providers/gemini";
import { GroqWebViewProvider } from "../providers/groq";
Expand Down Expand Up @@ -38,7 +42,7 @@ export abstract class EventGenerator implements IEventGenerator {
constructor(
private readonly action: string,
_context: vscode.ExtensionContext,
errorMessage?: string
errorMessage?: string,
) {
this.context = _context;
this.error = errorMessage;
Expand Down Expand Up @@ -68,21 +72,23 @@ export abstract class EventGenerator implements IEventGenerator {
return getConfigValue(configKey);
}

protected createModel(): { generativeAi: string; model: any; modelName: string } | undefined {
protected createModel():
| { generativeAi: string; model: any; modelName: string }
| undefined {
try {
let model;
let modelName = "";
if (!this.generativeAi) {
vscodeErrorMessage(
"Configuration not found. Go to settings, search for Your coding buddy. Fill up the model and model name"
"Configuration not found. Go to settings, search for Your coding buddy. Fill up the model and model name",
);
}
if (this.generativeAi === generativeAiModels.GROQ) {
const apiKey = this.groqApiKey;
modelName = this.groqModel;
if (!apiKey || !modelName) {
vscodeErrorMessage(
"Configuration not found. Go to settings, search for Your coding buddy. Fill up the model and model name"
"Configuration not found. Go to settings, search for Your coding buddy. Fill up the model and model name",
);
}
model = this.createGroqModel(apiKey);
Expand All @@ -108,7 +114,9 @@ export abstract class EventGenerator implements IEventGenerator {
return { generativeAi: this.generativeAi, model, modelName };
} catch (error) {
console.error("Error creating model:", error);
vscode.window.showErrorMessage("An error occurred while creating the model. Please try again.");
vscode.window.showErrorMessage(
"An error occurred while creating the model. Please try again.",
);
}
}

Expand Down Expand Up @@ -145,7 +153,9 @@ export abstract class EventGenerator implements IEventGenerator {
return new Groq({ apiKey });
}

protected async generateModelResponse(text: string): Promise<string | Anthropic.Messages.Message | undefined> {
protected async generateModelResponse(
text: string,
): Promise<string | Anthropic.Messages.Message | undefined> {
try {
const activeModel = this.createModel();
if (!activeModel) {
Expand Down Expand Up @@ -182,7 +192,7 @@ export abstract class EventGenerator implements IEventGenerator {

if (!response) {
throw new Error(
"Could not generate response. Check your settings, ensure the API keys and Model Name is added properly."
"Could not generate response. Check your settings, ensure the API keys and Model Name is added properly.",
);
}
if (this.action.includes("chart")) {
Expand All @@ -191,7 +201,9 @@ export abstract class EventGenerator implements IEventGenerator {
return response;
} catch (error) {
console.error("Error generating response:", error);
vscode.window.showErrorMessage("An error occurred while generating the response. Please try again.");
vscode.window.showErrorMessage(
"An error occurred while generating the response. Please try again.",
);
}
}

Expand All @@ -202,12 +214,19 @@ export abstract class EventGenerator implements IEventGenerator {
return inputString;
}

async generateGeminiResponse(model: any, text: string): Promise<string | undefined> {
async generateGeminiResponse(
model: any,
text: string,
): Promise<string | undefined> {
const result = await model.generateContent(text);
return result ? await result.response.text() : undefined;
}

private async anthropicResponse(model: Anthropic, generativeAiModel: string, userPrompt: string) {
private async anthropicResponse(
model: Anthropic,
generativeAiModel: string,
userPrompt: string,
) {
try {
const response = await model.messages.create({
model: generativeAiModel,
Expand All @@ -218,14 +237,22 @@ export abstract class EventGenerator implements IEventGenerator {
return response.content[0].text;
} catch (error) {
console.error("Error generating response:", error);
vscode.window.showErrorMessage("An error occurred while generating the response. Please try again.");
vscode.window.showErrorMessage(
"An error occurred while generating the response. Please try again.",
);
return;
}
}

private async groqResponse(model: Groq, prompt: string, generativeAiModel: string): Promise<string | undefined> {
private async groqResponse(
model: Groq,
prompt: string,
generativeAiModel: string,
): Promise<string | undefined> {
try {
const chatHistory = Memory.has(COMMON.ANTHROPIC_CHAT_HISTORY) ? Memory.get(COMMON.GROQ_CHAT_HISTORY) : [];
const chatHistory = Memory.has(COMMON.ANTHROPIC_CHAT_HISTORY)
? Memory.get(COMMON.GROQ_CHAT_HISTORY)
: [];
const params = {
messages: [
...chatHistory,
Expand All @@ -237,11 +264,14 @@ export abstract class EventGenerator implements IEventGenerator {
model: generativeAiModel,
};

const completion: Groq.Chat.ChatCompletion = await model.chat.completions.create(params);
const completion: Groq.Chat.ChatCompletion =
await model.chat.completions.create(params);
return completion.choices[0]?.message?.content ?? undefined;
} catch (error) {
console.error("Error generating response:", error);
vscode.window.showErrorMessage("An error occurred while generating the response. Please try again.");
vscode.window.showErrorMessage(
"An error occurred while generating the response. Please try again.",
);
return;
}
}
Expand All @@ -250,7 +280,9 @@ export abstract class EventGenerator implements IEventGenerator {

abstract createPrompt(text?: string): any;

async generateResponse(message?: string): Promise<string | Anthropic.Messages.Message | undefined> {
async generateResponse(
message?: string,
): Promise<string | Anthropic.Messages.Message | undefined> {
this.showInformationMessage();
let prompt;
const selectedCode = this.getSelectedWindowArea();
Expand All @@ -262,7 +294,9 @@ export abstract class EventGenerator implements IEventGenerator {
if (message && selectedCode) {
prompt = await this.createPrompt(`${message} \n ${selectedCode}`);
} else {
message ? (prompt = await this.createPrompt(message)) : (prompt = await this.createPrompt(selectedCode));
message
? (prompt = await this.createPrompt(message))
: (prompt = await this.createPrompt(selectedCode));
}

if (!prompt) {
Expand Down Expand Up @@ -345,19 +379,25 @@ export abstract class EventGenerator implements IEventGenerator {
placeHolder: "Enter instructions for CodeBuddy",
ignoreFocusOut: true,
validateInput: (text) => {
return text === "" ? "Enter instructions for CodeBuddy or press Escape to close chat box" : null;
return text === ""
? "Enter instructions for CodeBuddy or press Escape to close chat box"
: null;
},
});
return userPrompt;
} catch (error) {
vscode.window.showInformationMessage(`Error occured while getting user prompt`);
vscode.window.showInformationMessage(
`Error occured while getting user prompt`,
);
console.log(error);
}
}

async execute(message?: string): Promise<void> {
let prompt: string | undefined;
const response = (await this.generateResponse(prompt ? prompt : message)) as string;
const response = (await this.generateResponse(
prompt ? prompt : message,
)) as string;
if (!response) {
vscode.window.showErrorMessage("model not reponding, try again later");
return;
Expand Down
6 changes: 5 additions & 1 deletion src/emitter/agent-emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
import * as vscode from "vscode";

export class AgentEventEmitter extends BaseEmitter<IAgentEventMap> {
onStatus: vscode.Event<IStatusEvent> = this.createEvent("onStatus");
onStatusChange: vscode.Event<IStatusEvent> = this.createEvent("onStatus");
onError: vscode.Event<IErrorEvent> = this.createEvent("onError");

public emitError(message: string, code: string) {
Expand All @@ -28,4 +28,8 @@ export class AgentEventEmitter extends BaseEmitter<IAgentEventMap> {
timestamp: Date.now(),
});
}

public dispose(): void {
super.dispose();
}
}
22 changes: 19 additions & 3 deletions src/emitter/emitter.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,39 @@
import * as vscode from "vscode";
import { Logger } from "../infrastructure/logger/logger";
export class BaseEmitter<EventMap> {
export class BaseEmitter<EventMap extends Record<string, any>> {
protected logger: Logger;
constructor() {
this.logger = new Logger("BaseEmitter");
}
private readonly emitters: Map<keyof EventMap, vscode.EventEmitter<any>> =
new Map();

/**
* Creates a new event for the given event name, reusing an existing emitter if one is already registered.
* @param name The name of the event to create.
* @returns The event that was created or retrieved.
*/
protected createEvent<K extends keyof EventMap>(
name: K,
): vscode.Event<EventMap[K]> {
try {
const emitter = new vscode.EventEmitter<EventMap[K]>();
this.emitters.set(name, emitter);
let emitter = this.emitters.get(name);
if (!emitter) {
emitter = new vscode.EventEmitter<EventMap[K]>();
this.emitters.set(name, emitter);
}
return emitter.event;
} catch (error) {
this.logger.error("Error generating embeddings", error);
throw new Error("Failed to generate embeddings");
}
}

/**
* Emits the given event with the provided data, if an emitter exists for the event name.
* @param name The name of the event to emit.
* @param data The data to emit with the event.
*/
protected emit<K extends keyof EventMap>(name: K, data: EventMap[K]): void {
try {
const emitter = this.emitters.get(name);
Expand All @@ -31,6 +44,9 @@ export class BaseEmitter<EventMap> {
}
}

/**
* Disposes of all stored event emitters, freeing up any system resources they were using.
*/
public dispose(): void {
this.emitters.forEach((emitter) => emitter.dispose());
}
Expand Down
Loading

0 comments on commit 0084bef

Please sign in to comment.