mirror of
https://github.com/ggml-org/llama.vscode.git
synced 2026-05-07 01:15:23 +00:00
Compare commits
1 commit
master
...
menu_refac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5cbbe87c17 |
9 changed files with 382 additions and 253 deletions
|
|
@ -23,6 +23,7 @@ import { HfModelStrategy } from "./services/hf-model-strategy";
|
|||
import { LocalModelStrategy } from "./services/local-model-strategy";
|
||||
import { ExternalModelStrategy } from "./services/external-model-strategy";
|
||||
import { EnvService } from "./services/env-service";
|
||||
import { AgentService } from "./services/agent-service";
|
||||
|
||||
export class Application {
|
||||
private static instance: Application;
|
||||
|
|
@ -49,6 +50,7 @@ export class Application {
|
|||
public localModelStrategy: LocalModelStrategy
|
||||
public externalModelStrategy: ExternalModelStrategy
|
||||
public envService: EnvService
|
||||
public agentService: AgentService
|
||||
|
||||
private constructor(context: vscode.ExtensionContext) {
|
||||
this.configuration = new Configuration()
|
||||
|
|
@ -75,6 +77,7 @@ export class Application {
|
|||
this.externalModelStrategy = new ExternalModelStrategy(this)
|
||||
this.modelService = new ModelService(this)
|
||||
this.envService = new EnvService(this)
|
||||
this.agentService = new AgentService(this)
|
||||
}
|
||||
|
||||
public static getInstance(context: vscode.ExtensionContext): Application {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {LlamaWebviewProvider} from './llama-webview-provider'
|
|||
import { Utils } from './utils';
|
||||
import { Env, LlmModel } from './types';
|
||||
import { env } from 'process';
|
||||
import { SETTING_NAME_FOR_LIST } from './constants';
|
||||
import { PERSISTENCE_KEYS, SETTING_NAME_FOR_LIST } from './constants';
|
||||
|
||||
export class Architect {
|
||||
private app: Application
|
||||
|
|
@ -42,10 +42,10 @@ export class Architect {
|
|||
|
||||
}
|
||||
}
|
||||
let lastChat = this.app.persistence.getValue("selectedChat")
|
||||
let lastChat = this.app.persistence.getValue(PERSISTENCE_KEYS.SELECTED_CHAT)
|
||||
if (lastChat) this.app.menu.selectUpdateChat(lastChat)
|
||||
let lastAgent = this.app.persistence.getValue("selectedAgent")
|
||||
if (lastAgent) this.app.menu.selectAgent(lastAgent)
|
||||
let lastAgent = this.app.persistence.getValue(PERSISTENCE_KEYS.SELECTED_AGENT)
|
||||
if (lastAgent) this.app.agentService.selectAgent(lastAgent)
|
||||
this.app.tools.init()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ export class LlamaAgent {
|
|||
}
|
||||
|
||||
selectChat = (chat: Chat) => {
|
||||
if (chat && chat.defaultAgent) this.app.menu.selectAgent(chat.defaultAgent);
|
||||
if (chat && chat.defaultAgent) this.app.agentService.selectAgent(chat.defaultAgent);
|
||||
this.resetMessages();
|
||||
|
||||
if (chat){
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ export class LlamaWebviewProvider implements vscode.WebviewViewProvider {
|
|||
await this.app.menu.deselectAndClearModel(ModelType.Tools);
|
||||
break;
|
||||
case 'deselectAgent':
|
||||
await this.app.menu.deselectAgent();
|
||||
await this.app.agentService.deselectAgent();
|
||||
break;
|
||||
case 'showCompletionModel':
|
||||
this.app.modelService.showModelDetails(this.app.menu.getComplModel());
|
||||
|
|
@ -109,11 +109,11 @@ export class LlamaWebviewProvider implements vscode.WebviewViewProvider {
|
|||
this.app.modelService.showModelDetails(this.app.menu.getToolsModel());
|
||||
break;
|
||||
case 'showAgentDetails':
|
||||
this.app.menu.showAgentDetails(this.app.menu.getAgent())
|
||||
this.app.agentService.showAgentDetails(this.app.menu.getAgent())
|
||||
break;
|
||||
case 'selectAgent':
|
||||
let agentsList = this.app.configuration.agents_list
|
||||
await this.app.menu.selectAgentFromList(agentsList)
|
||||
await this.app.agentService.pickAndSelectAgent(agentsList)
|
||||
break;
|
||||
case 'chatWithAI':
|
||||
this.app.askAi.closeChatWithAi(false);
|
||||
|
|
|
|||
265
src/menu.ts
265
src/menu.ts
|
|
@ -5,7 +5,7 @@ import { Utils } from "./utils";
|
|||
import { Configuration } from "./configuration";
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { ModelType, LOCAL_MODEL_TEMPLATES, HF_MODEL_TEMPLATES, SETTING_TO_MODEL_TYPE, MODEL_TYPE_CONFIG, AGENT_NAME, UI_TEXT_KEYS, PERSISTENCE_KEYS, PREDEFINED_LISTS_KEYS, SETTING_NAME_FOR_LIST } from "./constants";
|
||||
import { ModelType, AGENT_NAME, UI_TEXT_KEYS, PERSISTENCE_KEYS, PREDEFINED_LISTS_KEYS } from "./constants";
|
||||
import { PREDEFINED_LISTS } from "./lists";
|
||||
|
||||
export class Menu {
|
||||
|
|
@ -18,6 +18,7 @@ export class Menu {
|
|||
private selectedEnv: Env = {name: ""}
|
||||
private selectedAgent: Agent = {name: "", systemInstruction: []}
|
||||
private selectedChat: Chat = {name:"", id:""}
|
||||
|
||||
private readonly startModelDetail = "Selects the model and if local also downloads the model (if not yet done) and starts a llama-server with it.";
|
||||
|
||||
constructor(application: Application) {
|
||||
|
|
@ -176,7 +177,10 @@ export class Menu {
|
|||
this.app.askAi.showChatWithAi(false, context);
|
||||
break;
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.chatWithAIAboutLlamaVscode):
|
||||
this.selectAgent(this.app.configuration.agents_list.find(a => a.name === AGENT_NAME.llamaVscodeHelp));
|
||||
const helpAgent = this.app.configuration.agents_list.find(a => a.name === AGENT_NAME.llamaVscodeHelp);
|
||||
if (helpAgent) {
|
||||
await this.app.agentService.selectAgent(helpAgent);
|
||||
}
|
||||
this.showAgentView();
|
||||
break;
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.showLlamaAgent) + " (Ctrl+Shif+A)":
|
||||
|
|
@ -214,9 +218,9 @@ export class Menu {
|
|||
if (envSelected) await this.app.envService.processActions(envSelected);
|
||||
break;
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.agents) ?? "":
|
||||
let agentsActions: vscode.QuickPickItem[] = this.getAgentActions();
|
||||
let agentsActions: vscode.QuickPickItem[] = this.app.agentService.getActions();
|
||||
let actionSelected = await vscode.window.showQuickPick(agentsActions);
|
||||
if (actionSelected) this.processAgentsActions(actionSelected);
|
||||
if (actionSelected) await this.app.agentService.processActions(actionSelected);
|
||||
break;
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.agentCommands) ?? "":
|
||||
let agentCommandsActions: vscode.QuickPickItem[] = this.getAgentCommandsActions();
|
||||
|
|
@ -331,43 +335,10 @@ export class Menu {
|
|||
}
|
||||
}
|
||||
|
||||
selectAgentFromList = async (agentsList: Agent[]) => {
|
||||
let allAgents = agentsList.concat(PREDEFINED_LISTS.get(PREDEFINED_LISTS_KEYS.AGENTS) as Agent[])
|
||||
let agentsItems: QuickPickItem[] = this.getStandardQpList(agentsList, "");
|
||||
agentsItems = agentsItems.concat(this.getStandardQpList(PREDEFINED_LISTS.get(PREDEFINED_LISTS_KEYS.AGENTS) as Agent[], "(predefined) ", agentsList.length));
|
||||
let lastUsedAgent = this.app.persistence.getValue("selectedAgent")
|
||||
if (lastUsedAgent) agentsItems.push({ label: (agentsItems.length+1) + ". Last used agent", description: lastUsedAgent.name });
|
||||
const agent = await vscode.window.showQuickPick(agentsItems);
|
||||
if (agent) {
|
||||
let futureAgent: Agent;
|
||||
if (agent.label.includes("Last used agent")){
|
||||
futureAgent = lastUsedAgent;
|
||||
|
||||
} else {
|
||||
futureAgent = allAgents[parseInt(agent.label.split(". ")[0], 10) - 1]
|
||||
}
|
||||
if(!futureAgent){
|
||||
vscode.window.showWarningMessage("No agent selected. There is no last used agent.");
|
||||
return;
|
||||
}
|
||||
this.selectedAgent = futureAgent;
|
||||
await this.selectAgent(futureAgent)
|
||||
this.app.llamaWebviewProvider.updateLlamaView();
|
||||
// TODO ? when model is added to the agent type - select it
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
selectAgent = async (agent: Agent) => {
|
||||
public setSelectedAgent(agent: Agent): void {
|
||||
this.selectedAgent = agent;
|
||||
if(!agent.tools || agent.tools.length == 0) return;
|
||||
|
||||
for (let toolFunc of this.app.tools.toolsFunc){
|
||||
let toolName = toolFunc[0];
|
||||
this.app.configuration.updateConfigValue("tool_" + toolName + "_enabled", agent.tools.includes(toolName))
|
||||
}
|
||||
await this.app.persistence.setValue(PERSISTENCE_KEYS.SELECTED_AGENT, this.selectedAgent);
|
||||
this.app.llamaWebviewProvider.updateLlamaView();
|
||||
if (agent.name) vscode.window.showInformationMessage("Agent " + agent.name + " is selected.")
|
||||
}
|
||||
|
||||
private async processModelActions(modelType: ModelType) {
|
||||
|
|
@ -378,8 +349,6 @@ export class Menu {
|
|||
}
|
||||
}
|
||||
|
||||
// selectStartModel removed, handled by ModelService
|
||||
|
||||
public async showAgentView() {
|
||||
let isModelAvailable = await this.checkForToolsModel();
|
||||
if (isModelAvailable) {
|
||||
|
|
@ -453,51 +422,9 @@ export class Menu {
|
|||
|
||||
|
||||
|
||||
private getAgentActions(): vscode.QuickPickItem[] {
|
||||
return [
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.selectStartAgent) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.deselectStopAgent) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.addAgent) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.viewAgentDetails) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.deleteAgent) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.exportAgent) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.importAgent) ?? ""
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
private getAgentCommandsActions(): vscode.QuickPickItem[] {
|
||||
return [
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.addAgentCommand) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.viewAgentCommandDetails) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.deleteAgentCommand) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.exportAgentCommand) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.importAgentCommand) ?? ""
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
private getChatActions(): vscode.QuickPickItem[] {
|
||||
|
|
@ -541,31 +468,11 @@ export class Menu {
|
|||
);
|
||||
}
|
||||
|
||||
private async viewAgentFromList(agentsList: any[]) {
|
||||
let allAgents = agentsList.concat(PREDEFINED_LISTS.get(PREDEFINED_LISTS_KEYS.AGENTS) as Agent[])
|
||||
let agentsItems: QuickPickItem[] = this.getStandardQpList(agentsList, "");
|
||||
agentsItems = agentsItems.concat(this.getStandardQpList(PREDEFINED_LISTS.get(PREDEFINED_LISTS_KEYS.AGENTS) as Agent[], "(predefined) ", agentsList.length));
|
||||
let agent = await vscode.window.showQuickPick(agentsItems);
|
||||
if (agent) {
|
||||
let agentIndex = parseInt(agent.label.split(". ")[0], 10) - 1;
|
||||
let selectedAgent = allAgents[agentIndex];
|
||||
await this.showAgentDetails(selectedAgent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async showAgentDetails(selectedAgent: any) {
|
||||
await Utils.showOkDialog(
|
||||
this.getAgentDetailsAsString(selectedAgent)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private getAgentDetailsAsString(selectedAgent: Agent): string {
|
||||
return "Agent details: " +
|
||||
"\nname: " + selectedAgent.name +
|
||||
"\ndescription: " + selectedAgent.description +
|
||||
"\nsystem prompt: \n" + selectedAgent.systemInstruction.join("\n") +
|
||||
"\n\ntools: " + (selectedAgent.tools ? selectedAgent.tools.join(", ") : "");
|
||||
}
|
||||
|
||||
|
||||
private async viewAgentCommandFromList(agentCommands: any[]) {
|
||||
let allAgentCommands = agentCommands.concat(PREDEFINED_LISTS.get(PREDEFINED_LISTS_KEYS.AGENT_COMMANDS) as Agent[])
|
||||
|
|
@ -609,16 +516,7 @@ export class Menu {
|
|||
"\n\ncontext: " + (selectedAgentCommand.context ? selectedAgentCommand.context.join(", ") : "");
|
||||
}
|
||||
|
||||
private async persistAgentToSetting(newAgent: Agent, agentsList: any[], settingName: string) {
|
||||
let modelDetails = this.getAgentDetailsAsString(newAgent);
|
||||
const shouldAddModel = await Utils.confirmAction("A new agent will be added. Do you want to add the agent?", modelDetails);
|
||||
|
||||
if (shouldAddModel) {
|
||||
agentsList.push(newAgent);
|
||||
this.app.configuration.updateConfigValue(settingName, agentsList);
|
||||
vscode.window.showInformationMessage("The agent is added.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async persistAgentCommandToSetting(newAgentCommand: AgentCommand, agentCommands: any[], settingName: string) {
|
||||
let modelDetails = this.getAgentCommandDetailsAsString(newAgentCommand);
|
||||
|
|
@ -631,32 +529,7 @@ export class Menu {
|
|||
}
|
||||
}
|
||||
|
||||
private async importAgentToList(agentList: any[], settingName: string) {
|
||||
let name = "";
|
||||
const uris = await vscode.window.showOpenDialog({
|
||||
canSelectMany: false,
|
||||
openLabel: 'Import Agent',
|
||||
filters: {
|
||||
'Agent Files': ['json'],
|
||||
'All Files': ['*']
|
||||
},
|
||||
});
|
||||
|
||||
if (!uris || uris.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const filePath = uris[0].fsPath;
|
||||
|
||||
const fileContent = fs.readFileSync(filePath, 'utf8');
|
||||
const newAgent = JSON.parse(fileContent);
|
||||
// Sanitize imported agent
|
||||
if (newAgent.name) newAgent.name = this.app.modelService.sanitizeInput(newAgent.name);
|
||||
if (newAgent.description) newAgent.description = this.app.modelService.sanitizeInput(newAgent.description);
|
||||
if (newAgent.systemInstruction) newAgent.systemInstruction = newAgent.systemInstruction.map((s: string) => this.app.modelService.sanitizeInput(s));
|
||||
|
||||
await this.persistAgentToSetting(newAgent, agentList, settingName);
|
||||
}
|
||||
|
||||
|
||||
private async importAgentCommandToList(agentCommands: any[], settingName: string) {
|
||||
let name = "";
|
||||
|
|
@ -750,38 +623,7 @@ export class Menu {
|
|||
"\napi key required: " + this.selectedToolsModel.isKeyRequired;
|
||||
}
|
||||
|
||||
private async exportAgentFromList(agentsList: any[]) {
|
||||
let allAgents = agentsList.concat(PREDEFINED_LISTS.get(PREDEFINED_LISTS_KEYS.AGENTS) as Agent[])
|
||||
let agentsItems: QuickPickItem[] = this.getStandardQpList(agentsList, "");
|
||||
agentsItems = agentsItems.concat(this.getStandardQpList(PREDEFINED_LISTS.get(PREDEFINED_LISTS_KEYS.AGENTS) as Agent[], "(predefined) ", agentsList.length));
|
||||
let agent = await vscode.window.showQuickPick(agentsItems);
|
||||
if (agent) {
|
||||
let modelIndex = parseInt(agent.label.split(". ")[0], 10) - 1;
|
||||
let selectedAgent = allAgents[modelIndex];
|
||||
let shouldExport = await Utils.showYesNoDialog("Do you want to export the following agent? \n\n" +
|
||||
this.getAgentCommandDetailsAsString(selectedAgent)
|
||||
);
|
||||
|
||||
if (shouldExport){
|
||||
const uri = await vscode.window.showSaveDialog({
|
||||
defaultUri: vscode.Uri.file(path.join(vscode.workspace.rootPath || '', selectedAgent.name+'.json')),
|
||||
filters: {
|
||||
'Agent Files': ['json'],
|
||||
'All Files': ['*']
|
||||
},
|
||||
saveLabel: 'Export Agent'
|
||||
});
|
||||
|
||||
if (!uri) {
|
||||
return;
|
||||
}
|
||||
|
||||
const jsonContent = JSON.stringify(selectedAgent, null, 2);
|
||||
fs.writeFileSync(uri.fsPath, jsonContent, 'utf8');
|
||||
vscode.window.showInformationMessage("Agent is saved.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async exportAgentCommandFromList(agentCommands: any[]) {
|
||||
let allAgentCommands = agentCommands.concat(PREDEFINED_LISTS.get(PREDEFINED_LISTS_KEYS.AGENT_COMMANDS) as Agent[])
|
||||
|
|
@ -1001,39 +843,26 @@ export class Menu {
|
|||
|
||||
isChatSelected = (): boolean => {
|
||||
return this.selectedChat != undefined && this.selectedChat.name.trim() != "";
|
||||
}
|
||||
}
|
||||
|
||||
// process*ModelsActions removed, handled by ModelService.processActions
|
||||
// processEnvActions moved to EnvService.processActions
|
||||
|
||||
processAgentsActions = async (selected:vscode.QuickPickItem) => {
|
||||
switch (selected.label) {
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.selectStartAgent):
|
||||
await this.selectAgentFromList(this.app.configuration.agents_list);
|
||||
break;
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.addAgent):
|
||||
// await this.addModelToList(toolsTypeDetails);
|
||||
Utils.showOkDialog("You could add an agent in setting agents_list or use export, modify and import.")
|
||||
break;
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.deleteAgent):
|
||||
// await this.deleteModelFromList(this.app.configuration.tools_models_list, "tools_models_list");
|
||||
Utils.showOkDialog("You could delete an agent in setting agents_list")
|
||||
break;
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.viewAgentDetails):
|
||||
await this.viewAgentFromList(this.app.configuration.agents_list)
|
||||
break;
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.deselectStopAgent):
|
||||
// await this.deselectStopModel(this.app.llamaServer.killToolsCmd, "selectedToolsModel");
|
||||
this.selectedAgent = {name: "", systemInstruction: []};
|
||||
vscode.window.showInformationMessage("The agent is deselected.")
|
||||
break;
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.exportAgent):
|
||||
await this.exportAgentFromList(this.app.configuration.agents_list)
|
||||
break;
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.importAgent):
|
||||
await this.importAgentToList(this.app.configuration.agents_list, SETTING_NAME_FOR_LIST.AGENTS)
|
||||
break;
|
||||
}
|
||||
private getAgentCommandsActions(): vscode.QuickPickItem[] {
|
||||
return [
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.addAgentCommand) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.viewAgentCommandDetails) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.deleteAgentCommand) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.exportAgentCommand) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.importAgentCommand) ?? ""
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
processAgentCommandsActions = async (selected:vscode.QuickPickItem) => {
|
||||
|
|
@ -1121,23 +950,5 @@ export class Menu {
|
|||
public showEnvView() {
|
||||
vscode.commands.executeCommand('extension.showLlamaWebview');
|
||||
setTimeout(() => this.app.llamaWebviewProvider.setView("addenv"), 500);
|
||||
}
|
||||
|
||||
public deselectAgent() {
|
||||
this.selectAgent({
|
||||
name: "",
|
||||
systemInstruction: [],
|
||||
tools: [
|
||||
"run_terminal_command",
|
||||
"search_source",
|
||||
"read_file",
|
||||
"list_directory",
|
||||
"regex_search",
|
||||
"delete_file",
|
||||
"get_diff",
|
||||
"edit_file",
|
||||
"ask_user"
|
||||
]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
313
src/services/agent-service.ts
Normal file
313
src/services/agent-service.ts
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
|
||||
import * as vscode from "vscode";
|
||||
import { QuickPickItem } from "vscode";
|
||||
import { Application } from "../application";
|
||||
import { Agent } from "../types";
|
||||
import { Utils } from "../utils";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import { Configuration } from "../configuration";
|
||||
import { PREDEFINED_LISTS } from "../lists";
|
||||
import { UI_TEXT_KEYS, PERSISTENCE_KEYS, SETTING_NAME_FOR_LIST, PREDEFINED_LISTS_KEYS } from "../constants";
|
||||
|
||||
export class AgentService {
|
||||
private app: Application;
|
||||
|
||||
constructor(app: Application) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
getActions(): vscode.QuickPickItem[] {
|
||||
return [
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.selectStartAgent) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.deselectStopAgent) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.addAgent) ?? "",
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.viewAgentDetails) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.deleteAgent) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.exportAgent) ?? ""
|
||||
},
|
||||
{
|
||||
label: this.app.configuration.getUiText(UI_TEXT_KEYS.importAgent) ?? ""
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
async processActions(selected: vscode.QuickPickItem): Promise<void> {
|
||||
switch (selected.label) {
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.selectStartAgent):
|
||||
await this.pickAndSelectAgent(this.app.configuration.agents_list);
|
||||
break;
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.addAgent):
|
||||
await this.addAgent(this.app.configuration.agents_list, SETTING_NAME_FOR_LIST.AGENTS);
|
||||
break;
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.deleteAgent):
|
||||
await this.deleteAgent(this.app.configuration.agents_list, SETTING_NAME_FOR_LIST.AGENTS);
|
||||
break;
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.viewAgentDetails):
|
||||
await this.viewAgent(this.app.configuration.agents_list);
|
||||
break;
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.deselectStopAgent):
|
||||
await this.deselectAgent();
|
||||
break;
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.exportAgent):
|
||||
await this.exportAgent(this.app.configuration.agents_list);
|
||||
break;
|
||||
case this.app.configuration.getUiText(UI_TEXT_KEYS.importAgent):
|
||||
await this.importAgent(this.app.configuration.agents_list, SETTING_NAME_FOR_LIST.AGENTS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public async pickAndSelectAgent(agentsList: Agent[]): Promise<Agent | undefined> {
|
||||
let allAgents = agentsList.concat(PREDEFINED_LISTS.get(PREDEFINED_LISTS_KEYS.AGENTS) as Agent[]);
|
||||
let agentsItems: QuickPickItem[] = this.getStandardQpList(agentsList, "");
|
||||
agentsItems = agentsItems.concat(this.getStandardQpList(PREDEFINED_LISTS.get(PREDEFINED_LISTS_KEYS.AGENTS) as Agent[], "(predefined) ", agentsList.length));
|
||||
let lastUsedAgent = this.app.persistence.getValue(PERSISTENCE_KEYS.SELECTED_AGENT) as Agent;
|
||||
if (lastUsedAgent && lastUsedAgent.name.trim() !== "") {
|
||||
agentsItems.push({ label: (agentsItems.length + 1) + ". Last used agent", description: lastUsedAgent.name });
|
||||
}
|
||||
const agentItem = await vscode.window.showQuickPick(agentsItems);
|
||||
if (agentItem) {
|
||||
let selectedAgent: Agent;
|
||||
if (agentItem.label.includes("Last used agent")) {
|
||||
selectedAgent = lastUsedAgent;
|
||||
} else {
|
||||
const index = parseInt(agentItem.label.split(". ")[0], 10) - 1;
|
||||
selectedAgent = allAgents[index];
|
||||
}
|
||||
if (selectedAgent) {
|
||||
await this.selectAgent(selectedAgent);
|
||||
vscode.window.showInformationMessage(`Agent is selected: ${selectedAgent.name}`);
|
||||
return selectedAgent;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async selectAgent(agent: Agent): Promise<void> {
|
||||
this.app.menu.setSelectedAgent(agent);
|
||||
const allTools = Array.from(this.app.tools.toolsFunc.keys());
|
||||
for (let toolName of allTools) {
|
||||
this.app.configuration.updateConfigValue(`tool_${toolName}_enabled`, agent.tools?.includes(toolName) ?? false);
|
||||
}
|
||||
await this.app.persistence.setValue(PERSISTENCE_KEYS.SELECTED_AGENT, agent);
|
||||
this.app.llamaWebviewProvider.updateLlamaView();
|
||||
if (agent.name.trim() !== "") {
|
||||
vscode.window.showInformationMessage(`Agent ${agent.name} is selected.`);
|
||||
}
|
||||
}
|
||||
|
||||
async deselectAgent(): Promise<void> {
|
||||
const emptyAgent = { name: "", systemInstruction: [] };
|
||||
this.app.menu.setSelectedAgent(emptyAgent);
|
||||
const allTools = Array.from(this.app.tools.toolsFunc.keys());
|
||||
for (let toolName of allTools) {
|
||||
this.app.configuration.updateConfigValue(`tool_${toolName}_enabled`, true);
|
||||
}
|
||||
await this.app.persistence.setValue(PERSISTENCE_KEYS.SELECTED_AGENT, emptyAgent);
|
||||
this.app.llamaWebviewProvider.updateLlamaView();
|
||||
vscode.window.showInformationMessage("The agent is deselected.");
|
||||
}
|
||||
|
||||
async addAgent(agentsList: Agent[], settingName: string): Promise<void> {
|
||||
let name = await Utils.getValidatedInput(
|
||||
'name for your agent (required)',
|
||||
(input) => input.trim() !== '',
|
||||
5,
|
||||
{
|
||||
placeHolder: 'Enter a user friendly name for your agent (required)',
|
||||
value: ''
|
||||
}
|
||||
);
|
||||
if (name === undefined) {
|
||||
vscode.window.showInformationMessage("Agent addition cancelled.");
|
||||
return;
|
||||
}
|
||||
name = this.app.modelService.sanitizeInput(name);
|
||||
|
||||
let description = await vscode.window.showInputBox({
|
||||
placeHolder: 'description for the agent - what is the purpose, when to select etc. ',
|
||||
prompt: 'Enter description for the agent.',
|
||||
value: ''
|
||||
});
|
||||
description = this.app.modelService.sanitizeInput(description || '');
|
||||
|
||||
// Collect system instruction lines
|
||||
let systemInstruction: string[] = [];
|
||||
let line: string | undefined;
|
||||
do {
|
||||
line = await vscode.window.showInputBox({
|
||||
placeHolder: 'Enter a line for system instruction (empty to finish)',
|
||||
prompt: 'System instruction line',
|
||||
value: ''
|
||||
});
|
||||
if (line && line.trim() !== '') {
|
||||
systemInstruction.push(this.app.modelService.sanitizeInput(line));
|
||||
}
|
||||
} while (line && line.trim() !== '');
|
||||
|
||||
if (systemInstruction.length === 0) {
|
||||
vscode.window.showWarningMessage("No system instruction provided. Agent may not function properly.");
|
||||
}
|
||||
|
||||
// Select tools
|
||||
const availableTools = Array.from(this.app.tools.toolsFunc.keys()).map(tool => ({
|
||||
label: tool,
|
||||
picked: true // default all
|
||||
}));
|
||||
const selectedToolsItems = await vscode.window.showQuickPick(availableTools, {
|
||||
canPickMany: true,
|
||||
placeHolder: 'Select tools for the agent (Ctrl+click to select multiple)'
|
||||
});
|
||||
const tools = selectedToolsItems ? selectedToolsItems.map(item => item.label) : Array.from(this.app.tools.toolsFunc.keys());
|
||||
|
||||
let newAgent: Agent = {
|
||||
name: name,
|
||||
description: description,
|
||||
systemInstruction: systemInstruction,
|
||||
tools: tools
|
||||
};
|
||||
|
||||
await this.persistAgent(newAgent, agentsList, settingName);
|
||||
}
|
||||
|
||||
private async persistAgent(newAgent: Agent, agentsList: Agent[], settingName: string): Promise<void> {
|
||||
let agentDetails = this.getAgentDetailsAsString(newAgent);
|
||||
const shouldAddAgent = await Utils.confirmAction("A new agent will be added. Do you want to add the agent?", agentDetails);
|
||||
|
||||
if (shouldAddAgent) {
|
||||
agentsList.push(newAgent);
|
||||
this.app.configuration.updateConfigValue(settingName, agentsList);
|
||||
vscode.window.showInformationMessage("The agent is added.");
|
||||
}
|
||||
}
|
||||
|
||||
async deleteAgent(agentsList: Agent[], settingName: string): Promise<void> {
|
||||
const agentsItems: QuickPickItem[] = this.getStandardQpList(agentsList, "");
|
||||
const agentItem = await vscode.window.showQuickPick(agentsItems);
|
||||
if (agentItem) {
|
||||
let agentIndex = parseInt(agentItem.label.split(". ")[0], 10) - 1;
|
||||
const shouldDeleteAgent = await Utils.confirmAction("Are you sure you want to delete the following agent?",
|
||||
this.getAgentDetailsAsString(agentsList[agentIndex])
|
||||
);
|
||||
if (shouldDeleteAgent) {
|
||||
agentsList.splice(agentIndex, 1);
|
||||
this.app.configuration.updateConfigValue(settingName, agentsList);
|
||||
vscode.window.showInformationMessage("The agent is deleted.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async viewAgent(agentsList: Agent[]): Promise<void> {
|
||||
let allAgents = agentsList.concat(PREDEFINED_LISTS.get(PREDEFINED_LISTS_KEYS.AGENTS) as Agent[]);
|
||||
let agentsItems: QuickPickItem[] = this.getStandardQpList(agentsList, "");
|
||||
agentsItems = agentsItems.concat(this.getStandardQpList(PREDEFINED_LISTS.get(PREDEFINED_LISTS_KEYS.AGENTS) as Agent[], "(predefined) ", agentsList.length));
|
||||
let agentItem = await vscode.window.showQuickPick(agentsItems);
|
||||
if (agentItem) {
|
||||
let agentIndex = parseInt(agentItem.label.split(". ")[0], 10) - 1;
|
||||
let selectedAgent = allAgents[agentIndex];
|
||||
await this.showAgentDetails(selectedAgent);
|
||||
}
|
||||
}
|
||||
|
||||
public async showAgentDetails(selectedAgent: Agent) {
|
||||
let agentDetails = this.getAgentDetailsAsString(selectedAgent);
|
||||
await Utils.showOkDialog(agentDetails);
|
||||
}
|
||||
|
||||
async exportAgent(agentsList: Agent[]): Promise<void> {
|
||||
let allAgents = agentsList.concat(PREDEFINED_LISTS.get(PREDEFINED_LISTS_KEYS.AGENTS) as Agent[]);
|
||||
let agentsItems: QuickPickItem[] = this.getStandardQpList(agentsList, "");
|
||||
agentsItems = agentsItems.concat(this.getStandardQpList(PREDEFINED_LISTS.get(PREDEFINED_LISTS_KEYS.AGENTS) as Agent[], "(predefined) ", agentsList.length));
|
||||
let agentItem = await vscode.window.showQuickPick(agentsItems);
|
||||
if (agentItem) {
|
||||
let agentIndex = parseInt(agentItem.label.split(". ")[0], 10) - 1;
|
||||
let selectedAgent = allAgents[agentIndex];
|
||||
let shouldExport = await Utils.showYesNoDialog("Do you want to export the following agent? \n\n" +
|
||||
this.getAgentDetailsAsString(selectedAgent)
|
||||
);
|
||||
|
||||
if (shouldExport) {
|
||||
const uri = await vscode.window.showSaveDialog({
|
||||
defaultUri: vscode.Uri.file(path.join(vscode.workspace.rootPath || '', selectedAgent.name + '.json')),
|
||||
filters: {
|
||||
'Agent Files': ['json'],
|
||||
'All Files': ['*']
|
||||
},
|
||||
saveLabel: 'Export Agent'
|
||||
});
|
||||
|
||||
if (uri) {
|
||||
const jsonContent = JSON.stringify(selectedAgent, null, 2);
|
||||
fs.writeFileSync(uri.fsPath, jsonContent, 'utf8');
|
||||
vscode.window.showInformationMessage("Agent is saved.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async importAgent(agentsList: Agent[], settingName: string): Promise<void> {
|
||||
const uris = await vscode.window.showOpenDialog({
|
||||
canSelectMany: false,
|
||||
openLabel: 'Import Agent',
|
||||
filters: {
|
||||
'Agent Files': ['json'],
|
||||
'All Files': ['*']
|
||||
},
|
||||
});
|
||||
|
||||
if (!uris || uris.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const filePath = uris[0].fsPath;
|
||||
const fileContent = fs.readFileSync(filePath, 'utf8');
|
||||
let newAgent: Agent = JSON.parse(fileContent);
|
||||
|
||||
// Sanitize imported agent
|
||||
this.sanitizeAgent(newAgent);
|
||||
|
||||
await this.persistAgent(newAgent, agentsList, settingName);
|
||||
}
|
||||
|
||||
private sanitizeAgent(agent: Agent): void {
|
||||
if (agent.name) agent.name = this.app.modelService.sanitizeInput(agent.name);
|
||||
if (agent.description) agent.description = this.app.modelService.sanitizeInput(agent.description);
|
||||
if (agent.systemInstruction) {
|
||||
agent.systemInstruction = agent.systemInstruction.map((s: string) => this.app.modelService.sanitizeInput(s));
|
||||
}
|
||||
// tools are strings, no need
|
||||
}
|
||||
|
||||
public getAgentDetailsAsString(agent: Agent): string {
|
||||
return "Agent details: " +
|
||||
"\nname: " + agent.name +
|
||||
"\ndescription: " + agent.description +
|
||||
"\nsystem prompt: \n" + agent.systemInstruction.join("\n") +
|
||||
"\n\ntools: " + (agent.tools ? agent.tools.join(", ") : "");
|
||||
}
|
||||
|
||||
private getStandardQpList(list: Agent[], prefix: string, lastAgentNumber: number = 0): QuickPickItem[] {
|
||||
const items: QuickPickItem[] = [];
|
||||
let i = lastAgentNumber;
|
||||
for (let elem of list) {
|
||||
i++;
|
||||
items.push({
|
||||
label: i + ". " + prefix + elem.name,
|
||||
description: elem.description,
|
||||
});
|
||||
}
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
|
@ -183,7 +183,7 @@ export class EnvService {
|
|||
// Set agent
|
||||
const agent = env.agent ?? currentAgent;
|
||||
if (agent) {
|
||||
await this.app.menu.selectAgent(agent);
|
||||
await this.app.agentService.selectAgent(agent);
|
||||
}
|
||||
|
||||
// Set configs if specified in env
|
||||
|
|
@ -299,7 +299,7 @@ export class EnvService {
|
|||
this.app.menu.setSelectedModel(ModelType.Embeddings, { name: "", localStartCommand: "" });
|
||||
await this.app.llamaServer.killToolsCmd();
|
||||
this.app.menu.setSelectedModel(ModelType.Tools, { name: "", localStartCommand: "" });
|
||||
this.app.menu.deselectAgent();
|
||||
await this.app.agentService.deselectAgent();
|
||||
this.app.menu.setSelectedEnv({ name: "" });
|
||||
this.app.llamaWebviewProvider.updateLlamaView();
|
||||
vscode.window.showInformationMessage("Env, models and agent are deselected.")
|
||||
|
|
|
|||
|
|
@ -227,9 +227,6 @@ export class Tools {
|
|||
if (params.input == undefined) return "The input is not provided."
|
||||
let filePath = this.getFilePath(params.input);
|
||||
if (!filePath) return "The file is not provided.";
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return "File not found: " + filePath;
|
||||
}
|
||||
try {
|
||||
if (!this.app.configuration.tool_permit_file_changes){
|
||||
let [yesApply, yesDontAsk] = await Utils.showYesYesdontaskNoDialog("Do you permit file " + filePath + " to be changed?")
|
||||
|
|
|
|||
31
src/utils.ts
31
src/utils.ts
|
|
@ -576,21 +576,26 @@ export class Utils {
|
|||
const workspaceRoot = vscode.workspace.workspaceFolders[0].uri.fsPath;
|
||||
absolutePath = path.join(workspaceRoot, filePath);
|
||||
}
|
||||
// Ensure only \n is used for new line
|
||||
const fileExists = await fs.promises.access(absolutePath).then(() => true).catch(() => false);
|
||||
if (!fileExists){
|
||||
await fs.promises.mkdir(path.dirname(absolutePath), { recursive: true });
|
||||
try {
|
||||
const fileExists = await fs.promises.access(absolutePath).then(() => true).catch(() => false);
|
||||
if (!fileExists){
|
||||
await fs.promises.mkdir(path.dirname(absolutePath), { recursive: true });
|
||||
await fs.promises.writeFile(absolutePath, result);
|
||||
}
|
||||
// Ensure only \n is used for new line
|
||||
result = (await fs.promises.readFile(absolutePath, 'utf-8')).split(/\r?\n/).join("\n");
|
||||
// Handle empty search text case
|
||||
if (searchText.trim() === '') {
|
||||
result += '\n' + replaceText;
|
||||
} else if (result.includes(searchText)) {
|
||||
result = result.split(searchText).join(replaceText);
|
||||
}
|
||||
|
||||
await fs.promises.writeFile(absolutePath, result);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) return "Error edititing file " + filePath + " - " + error.message;
|
||||
else return "Error edititing file " + filePath + " - " + error;
|
||||
}
|
||||
result = (await fs.promises.readFile(absolutePath, 'utf-8')).split(/\r?\n/).join("\n");
|
||||
// Handle empty search text case
|
||||
if (searchText.trim() === '') {
|
||||
result += '\n' + replaceText;
|
||||
} else if (result.includes(searchText)) {
|
||||
result = result.split(searchText).join(replaceText);
|
||||
}
|
||||
|
||||
await fs.promises.writeFile(absolutePath, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue