Compare commits

...

1 commit

Author SHA1 Message Date
igardev
6a2f298930 Enable skills usage 2025-12-31 17:29:42 +02:00
5 changed files with 98 additions and 4 deletions

7
package-lock.json generated
View file

@ -1,17 +1,18 @@
{
"name": "llama-vscode",
"version": "0.0.36",
"version": "0.0.38",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "llama-vscode",
"version": "0.0.36",
"version": "0.0.38",
"hasInstallScript": true,
"dependencies": {
"axios": "^1.1.2",
"globby": "^14.1.0",
"ignore": "^7.0.4",
"js-yaml": "^4.1.1",
"openai": "^4.80.1",
"picomatch": "^4.0.2",
"remark-gfm": "^4.0.1",
@ -1333,7 +1334,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true,
"license": "Python-2.0"
},
"node_modules/asynckit": {
@ -2883,7 +2883,6 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"dev": true,
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"

View file

@ -1918,6 +1918,11 @@
"default": false,
"description": "Show the details about the tools calls in UI - arguments and results."
},
"llama-vscode.skills_folder": {
"type": "string",
"default": "",
"description": "The folder, where are the skills are stored. If empty , <project_folder>/skills will be used."
},
"llama-vscode.language": {
"type": "string",
"default": "en",
@ -1993,6 +1998,7 @@
"axios": "^1.1.2",
"globby": "^14.1.0",
"ignore": "^7.0.4",
"js-yaml": "^4.1.1",
"openai": "^4.80.1",
"picomatch": "^4.0.2",
"remark-gfm": "^4.0.1",

View file

@ -46,6 +46,7 @@ export class Configuration {
ring_chunk_size = 64;
ring_scope = 1024;
ring_update_ms = 1000;
skills_folder = ""
language = "en";
// experimental - avoid using
@ -240,6 +241,7 @@ export class Configuration {
this.chats_max_tokens = Number(config.get<number>("chats_max_tokens"));
this.chats_summarize_old_msgs = Boolean(config.get<boolean>("chats_summarize_old_msgs"));
this.chats_msgs_keep = Number(config.get<number>("chats_msgs_keep"));
this.skills_folder = String(config.get<string>("skills_folder"));
this.language = String(config.get<string>("language"));
this.disabledLanguages = config.get<string[]>("disabledLanguages") || [];
this.enabled = Boolean(config.get<boolean>("enabled", true));

View file

@ -6,8 +6,13 @@ import { Chat } from "./types"
import { Plugin } from './plugin';
import * as fs from 'fs';
import { SUPPORTED_IMG_FILE_EXTS, UI_TEXT_KEYS } from "./constants";
import path from "path";
interface Frontmatter {
[key: string]: any;
}
interface Step {
id: string | number;
description: string;
@ -197,6 +202,11 @@ export class LlamaAgent {
this.summarize();
}
// Get the skills
const skillsFolder = this.app.configuration.skills_folder || Utils.getWorkspaceFolder() + "/" + "skills"
let skillsDesc = this.getSkillsDesc(skillsFolder)
if (skillsDesc) query += "\n\n" + skillsDesc
if (this.contexProjectFiles.size > 0){
query += "\n\nBelow is a context, attached by the user.\n"
for (const [key, value] of this.contexProjectFiles) {
@ -432,4 +442,72 @@ export class LlamaAgent {
}
return itemContext;
}
private getSkillsDesc(skillsFolder: string): string {
let desc = ""
if (fs.existsSync(skillsFolder)) {
desc += "<available_skills>"
const items = fs.readdirSync(skillsFolder, { withFileTypes: true });
const folders = items
.filter(item => item.isDirectory())
.map(item => item.name);
for(let folder in folders){
const skillsFile = path.join(skillsFolder, folders[folder], "SKILL.md");
if (fs.existsSync(skillsFile)){
desc += "<skill>"
const frontMatter = this.parseFrontmatter(skillsFile)
desc += `<name>${frontMatter.name}</name>`
desc += `<description>${frontMatter.description}</description>`
desc += `<location>${skillsFile}</location>`
desc += "</skill>"
}
}
desc += "</available_skills>"
}
return desc;
}
private parseFrontmatter(filePath: string): Frontmatter {
try {
const fileContent = fs.readFileSync(filePath, 'utf-8');
// Match frontmatter between --- delimiters
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n?/;
const match = fileContent.match(frontmatterRegex);
if (!match) {
return { frontmatter: {}, content: fileContent };
}
const frontmatterText = match[1];
const content = fileContent.slice(match[0].length);
// Parse frontmatter (assuming YAML format)
const frontmatter: Frontmatter = {};
const lines = frontmatterText.split('\n');
for (const line of lines) {
const colonIndex = line.indexOf(':');
if (colonIndex > 0) {
const key = line.slice(0, colonIndex).trim();
const value = line.slice(colonIndex + 1).trim();
// Try to parse as JSON-like values
try {
frontmatter[key] = JSON.parse(value);
} catch {
// Remove quotes if present
frontmatter[key] = value.replace(/^['"](.*)['"]$/, '$1');
}
}
}
return frontmatter;
} catch (error) {
vscode.window.showErrorMessage(`Failed to read or parse file: ${error}`);
return {}
}
}
}

View file

@ -917,4 +917,13 @@ export class Utils {
}
return filePath;
}
static getWorkspaceFolder = () => {
const workspaceFolders = vscode.workspace.workspaceFolders;
if (!vscode.workspace.workspaceFolders || vscode.workspace.workspaceFolders.length === 0) {
return "";
} else {
return vscode.workspace.workspaceFolders[0].uri.fsPath;
}
}
}