Project Files
toolsProvider.js
"use strict";
/**
* High-Performance Tools โ toolsProvider
*
* 14 tools:
* file_ops ยท dir_ops ยท run_command ยท get_environment
* python_run ยท python_quality
* cpp ยท git
* fetch_url ยท search_web
* memory ยท list_models ยท spawn_agent ยท custom_tool
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.toolsProvider = void 0;
const sdk_1 = require("@lmstudio/sdk");
const promises_1 = require("fs/promises");
const fs_1 = require("fs");
const path_1 = require("path");
const os_1 = require("os");
const search_1 = require("./search");
const peers_1 = require("./peers");
const zod_1 = require("zod");
const config_1 = require("./config");
const sandbox_1 = require("./sandbox");
const memory_1 = require("./agents/memory");
const subagent_1 = require("./agents/subagent");
const dynamicTools_1 = require("./agents/dynamicTools");
// ---------------------------------------------------------------------------
// Internal helpers
// ---------------------------------------------------------------------------
function json(obj) {
return JSON.stringify(obj, null, 2);
}
function disabled(toolName) {
return `Tool '${toolName}' is disabled in plugin settings. Enable it under Settings โ Plugins โ high-perf-tools.`;
}
function stripHtml(html) {
return html
.replace(/<(script|style)[^>]*>[\s\S]*?<\/\1>/gi, " ")
.replace(/<[^>]+>/g, " ")
.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")
.replace(/ /g, " ").replace(/"/g, '"').replace(/'/g, "'")
.replace(/[ \t]+/g, " ")
.replace(/\n{3,}/g, "\n\n")
.trim();
}
async function fileExists(p) {
try {
await (0, promises_1.stat)(p);
return true;
}
catch {
return false;
}
}
/** Generate a simple unified diff between two strings (no external deps). */
function unifiedDiff(oldText, newText, label = "file") {
const oldLines = oldText.split("\n");
const newLines = newText.split("\n");
const lines = [`--- a/${label}`, `+++ b/${label}`];
// Basic LCS-free diff: find changed blocks with ยฑ3 context lines
let i = 0, j = 0;
const chunks = [];
while (i < oldLines.length || j < newLines.length) {
if (oldLines[i] === newLines[j]) {
chunks.push(` ${oldLines[i]}`);
i++;
j++;
}
else {
// Find next sync point (up to 8 lines ahead)
let oi = i, ni = j;
let found = false;
for (let d = 1; d <= 8 && !found; d++) {
for (let k = 0; k <= d; k++) {
if (oldLines[i + k] !== undefined && oldLines[i + k] === newLines[j + d - k]) {
for (let x = 0; x < k; x++)
chunks.push(`-${oldLines[i + x] ?? ""}`);
for (let x = 0; x < d - k; x++)
chunks.push(`+${newLines[j + x] ?? ""}`);
i += k;
j += d - k;
found = true;
break;
}
}
}
if (!found) {
if (i < oldLines.length)
chunks.push(`-${oldLines[i++]}`);
if (j < newLines.length)
chunks.push(`+${newLines[j++]}`);
}
}
}
// Collapse unchanged runs into @@ hunks with 3 lines of context
const CONTEXT = 3;
let inHunk = false;
const result = [lines[0], lines[1]];
for (let idx = 0; idx < chunks.length; idx++) {
const changed = chunks[idx][0] === "+" || chunks[idx][0] === "-";
if (changed) {
if (!inHunk) {
const ctx = Math.max(0, idx - CONTEXT);
result.push(`@@ -${ctx + 1} @@`);
for (let c = ctx; c < idx; c++)
result.push(chunks[c]);
inHunk = true;
}
result.push(chunks[idx]);
}
else if (inHunk) {
result.push(chunks[idx]);
// End hunk after CONTEXT unchanged lines
const remaining = chunks.slice(idx + 1).findIndex((l) => l[0] === "+" || l[0] === "-");
if (remaining === -1 || remaining >= CONTEXT)
inHunk = false;
}
}
return result.length > 2 ? result.join("\n") : "(no differences)";
}
/**
* Wrap a tool implementation so any thrown error is returned as a structured
* message the model can read and act on, instead of silently failing.
*/
function safe_impl(name, fn) {
return async (rawParams, ctx) => {
if (ctx.signal.aborted) {
return JSON.stringify({ tool_error: true, tool: name, error: "cancelled" });
}
try {
return await fn(rawParams, ctx);
}
catch (err) {
const msg = err instanceof Error ? err.message : String(err);
// Return a structured error the model can parse and self-correct from
return JSON.stringify({
tool_error: true,
tool: name,
error: msg,
hint: "Read the error above, fix the parameter causing the issue, and retry the tool call.",
}, null, 2);
}
};
}
// Shorthand coerced primitive schemas โ more lenient than strict zBool(false)/z.number()
const zBool = (def) => zod_1.z.coerce.boolean().default(def);
const zInt = (def) => zod_1.z.coerce.number().int().default(def);
const zNum = (def) => zod_1.z.coerce.number().default(def);
// ---------------------------------------------------------------------------
// Tools Provider
// ---------------------------------------------------------------------------
const toolsProvider = async (ctl) => {
const cfg = ctl.getPluginConfig(config_1.pluginConfigSchematics);
const ws = () => (0, sandbox_1.getWorkspace)(cfg.get("workspacePath"));
const timeout = () => cfg.get("commandTimeoutSeconds");
// Resolve the Python interpreter once (cached per provider instantiation).
// Re-reads config each call so switching envs in settings takes effect on next chat.
const py = async () => (0, sandbox_1.resolvePython)(cfg.get("pythonInterpreter"));
// Permission helpers
const canShell = () => cfg.get("allowShellCommands");
const canPython = () => cfg.get("allowPythonExecution");
const canCpp = () => cfg.get("allowCppCompilation");
const canPip = () => cfg.get("allowPipInstall");
const canGitWrite = () => cfg.get("allowGitWrite");
const preferClang = () => cfg.get("preferClang");
const searxng = () => cfg.get("searxngUrl").trim() || undefined;
const searchWindow = () => {
const v = cfg.get("searchRecencyWindow").trim().toLowerCase();
return (["day", "week", "month", "year"].includes(v) ? v : undefined);
};
const webSearch = (query, max, timeRange) => (0, search_1.webSearch)(query, max, 10_000, searxng(), timeRange ?? searchWindow());
const webPeerLoaded = await (0, peers_1.detectWebPeer)(ctl);
// Use a loose array type here to avoid strict schema validation cascading types
const tools = [
// =========================================================================
// FILESYSTEM
// =========================================================================
(0, sdk_1.tool)({
name: "file_ops",
description: (0, sdk_1.text) `
Filesystem operations on workspace files.
action: "read" โ read file contents (supports line ranges)
action: "write" โ write or append content to a file
action: "replace" โ surgically replace text in a file (literal or regex)
action: "diff" โ preview what a write/replace would change (no modification)
action: "delete" โ delete a file or directory
action: "move" โ move or rename a file/directory
action: "copy" โ copy a file
action: "info" โ return metadata (size, line count, permissions)
`,
parameters: {
action: zod_1.z.enum(["read", "write", "replace", "diff", "delete", "move", "copy", "info"])
.describe("Operation to perform"),
path: zod_1.z.string().describe("Relative path inside the workspace"),
start_line: zod_1.z.coerce.number().int().min(1).default(1).describe("read: first line to return (1-indexed)"),
end_line: zInt(0).describe("read: last line to return (0 = EOF)"),
content: zod_1.z.string().default("").describe("write: text content to write"),
append: zBool(false).describe("write: append instead of overwrite"),
search: zod_1.z.string().default("").describe("replace/diff: text or regex pattern to find"),
replacement: zod_1.z.string().default("").describe("replace/diff: replacement text"),
regex: zBool(false).describe("replace/diff: treat search as JS regex"),
count: zod_1.z.coerce.number().int().min(0).default(0).describe("replace: max replacements (0 = all)"),
mode: zod_1.z.enum(["write", "replace"]).default("write").describe("diff: preview mode"),
new_content: zod_1.z.string().default("").describe("diff(write): content that would be written"),
recursive: zBool(false).describe("delete: required for non-empty directories"),
dst: zod_1.z.string().default("").describe("move/copy: destination path"),
},
implementation: safe_impl("file_ops", async ({ action, path, start_line, end_line, content, append, search, replacement, regex, count, mode, new_content, recursive, dst, }) => {
if (action === "read") {
if (!path)
return "Error: 'path' parameter is required for read operations.";
const p = (0, sandbox_1.safe)(ws(), path);
if (!await fileExists(p))
return `File not found: ${path}`;
const s = (0, fs_1.statSync)(p);
if (s.size > 100 * 1024 * 1024)
return `File too large (${(s.size / 1e6).toFixed(1)} MB). Use start_line/end_line.`;
try {
const txt = await (0, promises_1.readFile)(p, "utf-8");
const lines = txt.split("\n");
const total = lines.length;
const from = start_line - 1;
const to = end_line > 0 ? end_line : total;
return `[Lines ${from + 1}โ${Math.min(to, total)} of ${total} | ${(0, path_1.relative)(ws(), p)}]\n` + lines.slice(from, to).join("\n");
}
catch {
const raw = await (0, promises_1.readFile)(p);
return `[Binary โ ${s.size} bytes]\n${raw.slice(0, 512).toString("hex").replace(/(.{2})/g, "$1 ")}`;
}
}
if (action === "write") {
const p = (0, sandbox_1.safe)(ws(), path);
await (0, promises_1.mkdir)((0, path_1.dirname)(p), { recursive: true });
if (append) {
await (0, promises_1.appendFile)(p, content, "utf-8");
}
else {
await (0, promises_1.writeFile)(p, content, "utf-8");
}
const s = (0, fs_1.statSync)(p);
return `${append ? "Appended" : "Wrote"} ${content.length} chars โ ${(0, path_1.relative)(ws(), p)} (${s.size} bytes on disk)`;
}
if (action === "replace") {
const p = (0, sandbox_1.safe)(ws(), path);
if (!await fileExists(p))
return `File not found: ${path}`;
const original = await (0, promises_1.readFile)(p, "utf-8");
let n = 0;
let result;
if (regex) {
const re = new RegExp(search, "g");
let replaced = 0;
result = original.replace(re, (match) => {
if (count > 0 && replaced >= count)
return match;
replaced++;
n++;
return replacement;
});
}
else {
if (!search)
return "Error: search string cannot be empty";
if (original.indexOf(search) === -1)
return `No matches for: ${search}`;
let pos = 0;
let found = 0;
result = "";
while (true) {
const i = original.indexOf(search, pos);
if (i === -1 || (count > 0 && found >= count)) {
result += original.slice(pos);
break;
}
result += original.slice(pos, i) + replacement;
pos = i + search.length;
found++;
n++;
}
}
if (n === 0)
return `No matches found for: ${search}`;
await (0, promises_1.writeFile)(p, result, "utf-8");
return `Made ${n} replacement(s) in ${(0, path_1.relative)(ws(), p)}`;
}
if (action === "diff") {
const p = (0, sandbox_1.safe)(ws(), path);
const original = await fileExists(p) ? await (0, promises_1.readFile)(p, "utf-8") : "";
const label = (0, path_1.relative)(ws(), p);
let proposed;
if (mode === "write") {
proposed = new_content;
}
else {
if (!search)
return "Error: search is required for mode=replace";
if (!original)
return `File not found: ${path}`;
proposed = regex ? original.replace(new RegExp(search, "g"), replacement) : original.split(search).join(replacement);
}
const diff = unifiedDiff(original, proposed, label);
const added = (diff.match(/^\+(?!\+\+)/mg) ?? []).length;
const removed = (diff.match(/^-(?!--)/mg) ?? []).length;
return [`--- diff preview: ${label} ---`, `+${added} lines -${removed} lines`, "", diff, "", `To apply: call file_ops with action="${mode === "write" ? "write" : "replace"}" and the same parameters.`].join("\n");
}
if (action === "delete") {
const p = (0, sandbox_1.safe)(ws(), path);
if (!await fileExists(p))
return `Not found: ${path}`;
const s = (0, fs_1.statSync)(p);
if (s.isDirectory()) {
await (0, promises_1.rm)(p, { recursive, force: false });
return `Deleted directory ${(0, path_1.relative)(ws(), p)}`;
}
await (0, promises_1.unlink)(p);
return `Deleted file ${(0, path_1.relative)(ws(), p)}`;
}
if (action === "move") {
const s = (0, sandbox_1.safe)(ws(), path);
const d = (0, sandbox_1.safe)(ws(), dst);
if (!await fileExists(s))
return `Not found: ${path}`;
await (0, promises_1.mkdir)((0, path_1.dirname)(d), { recursive: true });
await (0, promises_1.rename)(s, d);
return `Moved ${(0, path_1.relative)(ws(), s)} โ ${(0, path_1.relative)(ws(), d)}`;
}
if (action === "copy") {
const s = (0, sandbox_1.safe)(ws(), path);
const d = (0, sandbox_1.safe)(ws(), dst);
if (!await fileExists(s))
return `Not found: ${path}`;
await (0, promises_1.mkdir)((0, path_1.dirname)(d), { recursive: true });
await (0, promises_1.copyFile)(s, d);
return `Copied ${(0, path_1.relative)(ws(), s)} โ ${(0, path_1.relative)(ws(), d)}`;
}
if (action === "info") {
const p = (0, sandbox_1.safe)(ws(), path);
if (!await fileExists(p))
return `Not found: ${path}`;
const s = (0, fs_1.statSync)(p);
const info = {
path: (0, path_1.relative)(ws(), p), type: s.isDirectory() ? "directory" : "file",
size_bytes: s.size, modified: s.mtime.toISOString(), mode: (s.mode & 0o777).toString(8),
};
if (s.isFile()) {
try {
const c = await (0, promises_1.readFile)(p, "utf-8");
info.line_count = c.split("\n").length;
info.encoding = "utf-8";
}
catch {
info.encoding = "binary";
}
}
return json(info);
}
throw new Error(`Unknown action: ${action}`);
}),
}),
(0, sdk_1.tool)({
name: "dir_ops",
description: (0, sdk_1.text) `
Directory and search operations on the workspace.
action: "list" โ list files and directories with metadata
action: "mkdir" โ create a directory (and all missing parents)
action: "search" โ search for a string or regex across files (like grep)
`,
parameters: {
action: zod_1.z.enum(["list", "mkdir", "search"]).describe("Operation to perform"),
path: zod_1.z.string().default(".").describe("list/mkdir: directory path; search: directory to search"),
pattern: zod_1.z.string().default("").describe("list: extension/name filter; search: text or regex to find"),
recursive: zBool(false).describe("list: walk subdirectories"),
show_hidden: zBool(false).describe("list: include dot-files"),
max_entries: zod_1.z.coerce.number().int().min(1).max(10000).default(2000).describe("list: entry limit"),
file_extension: zod_1.z.string().default("").describe("search: restrict to files with this extension (e.g. '.py')"),
regex: zBool(false).describe("search: treat pattern as JS regex"),
case_sensitive: zBool(true).describe("search: case-sensitive matching"),
context_lines: zod_1.z.coerce.number().int().min(0).max(10).default(2).describe("search: lines of context around each match"),
max_matches: zod_1.z.coerce.number().int().min(1).max(500).default(200).describe("search: stop after this many matches"),
},
implementation: safe_impl("dir_ops", async ({ action, path, pattern, recursive, show_hidden, max_entries, file_extension, regex, case_sensitive, context_lines, max_matches, }) => {
if (action === "list") {
const p = (0, sandbox_1.safe)(ws(), path);
if (!await fileExists(p))
return `Directory not found: ${path}`;
const entries = [];
let truncated = false;
async function walkList(dir) {
if (entries.length >= max_entries) {
truncated = true;
return;
}
const items = await (0, promises_1.readdir)(dir, { withFileTypes: true });
for (const item of items) {
if (!show_hidden && item.name.startsWith("."))
continue;
if (pattern && !item.name.includes(pattern) && !item.name.endsWith(pattern))
continue;
if (entries.length >= max_entries) {
truncated = true;
return;
}
const full = (0, path_1.join)(dir, item.name);
const rel = (0, path_1.relative)(ws(), full);
if (item.isDirectory()) {
entries.push({ name: rel, type: "dir" });
if (recursive)
await walkList(full);
}
else {
try {
const st = (0, fs_1.statSync)(full);
entries.push({ name: rel, type: "file", size: st.size });
}
catch { /* skip */ }
}
}
}
await walkList(p);
return json({ entries, count: entries.length, truncated });
}
if (action === "mkdir") {
const p = (0, sandbox_1.safe)(ws(), path);
await (0, promises_1.mkdir)(p, { recursive: true });
return `Directory successfully created: ${(0, path_1.relative)(ws(), p)}`;
}
if (action === "search") {
const base = (0, sandbox_1.safe)(ws(), path);
const flags = case_sensitive ? "" : "i";
let re;
try {
re = new RegExp(regex ? pattern : pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), flags);
}
catch (e) {
return `Invalid regex: ${e.message}`;
}
const results = [];
let total = 0;
async function walkSearch(dir) {
const items = await (0, promises_1.readdir)(dir, { withFileTypes: true });
for (const item of items) {
if (item.name.startsWith("."))
continue;
const full = (0, path_1.join)(dir, item.name);
if (item.isDirectory()) {
await walkSearch(full);
continue;
}
if (file_extension && !item.name.endsWith(file_extension))
continue;
try {
const st = (0, fs_1.statSync)(full);
if (st.size > 20 * 1024 * 1024) {
results.push(`[skipped ${(0, path_1.relative)(ws(), full)}: ${(st.size / 1e6).toFixed(0)} MB]`);
continue;
}
const content = await (0, promises_1.readFile)(full, "utf-8");
const lines = content.split("\n");
for (let i = 0; i < lines.length; i++) {
if (re.test(lines[i])) {
if (++total > max_matches)
return;
const from = Math.max(0, i - context_lines);
const to = Math.min(lines.length - 1, i + context_lines);
const block = [`${(0, path_1.relative)(ws(), full)}:${i + 1}: ${lines[i]}`];
for (let c = from; c <= to; c++) {
if (c !== i)
block.push(` ${c + 1}: ${lines[c]}`);
}
results.push(block.join("\n"));
}
}
}
catch { /* skip binary/unreadable */ }
}
}
await walkSearch(base);
if (total === 0)
return `No matches for ${pattern} in ${path}`;
const header = total > max_matches ? `Found ${max_matches}+ matches (stopped at limit):\n\n` : `Found ${total} match(es):\n\n`;
return header + results.join("\n---\n");
}
throw new Error(`Unknown action: ${action}`);
}),
}),
// =========================================================================
// EXECUTION
// =========================================================================
(0, sdk_1.tool)({
name: "run_command",
description: (0, sdk_1.text) `
Run a shell command inside the workspace.
WARNING: This executes arbitrary commands โ the cwd sandbox only sets the starting
directory. Enable in Settings โ Plugins โ high-perf-tools โ Allow Shell Commands.
`,
parameters: {
command: zod_1.z.string().describe("Shell command string"),
cwd: zod_1.z.string().default(".").describe("Working directory relative to workspace"),
stdin: zod_1.z.string().default("").describe("Text piped to stdin"),
},
implementation: safe_impl("run_command", async ({ command, cwd, stdin }, ctx) => {
ctx.status(`Running: ${command.slice(0, 80)}`);
if (!canShell())
return disabled("run_command");
const dir = (0, sandbox_1.safe)(ws(), cwd);
const r = await (0, sandbox_1.runShell)(command, { cwd: dir, stdin: stdin || undefined, timeout: timeout() });
return json({ returncode: r.code, stdout: r.stdout, stderr: r.stderr, success: r.success });
}),
}),
(0, sdk_1.tool)({
name: "python_run",
description: (0, sdk_1.text) `
Python execution tools. Enable in Settings โ Allow Python Execution.
action: "code" โ execute a Python code snippet
action: "file" โ run a .py file from the workspace
action: "test" โ run pytest on a path
action: "pip_install" โ install packages with pip (requires Allow pip install)
action: "pip_list" โ list installed packages
`,
parameters: {
action: zod_1.z.enum(["code", "file", "test", "pip_install", "pip_list"]).describe("Python operation to run"),
code: zod_1.z.string().default("").describe("code: Python source code to execute"),
path: zod_1.z.string().default(".").describe("file: path to .py file; test: path to test file or directory"),
args: zod_1.z.string().default("").describe("file: space-separated arguments"),
test_pattern: zod_1.z.string().default("").describe("test: pytest -k filter pattern"),
verbose: zBool(true).describe("test: show individual test outcomes"),
extra_args: zod_1.z.string().default("").describe("test: additional pytest arguments"),
packages: zod_1.z.string().default("").describe("pip_install: space-separated package names"),
upgrade: zBool(false).describe("pip_install: pass --upgrade flag"),
outdated: zBool(false).describe("pip_list: show only outdated packages"),
stdin: zod_1.z.string().default("").describe("code/file: text piped to stdin"),
},
implementation: safe_impl("python_run", async ({ action, code, path, args, test_pattern, verbose, extra_args, packages, upgrade, outdated, stdin }, ctx) => {
if (!canPython())
return disabled("python_run");
if (action === "code") {
ctx.status("Running Python codeโฆ");
const tmp = (0, path_1.join)((0, os_1.tmpdir)(), `lms_py_${Date.now()}.py`);
try {
await (0, promises_1.writeFile)(tmp, code, "utf-8");
const r = await (0, sandbox_1.run)(await py(), [tmp], { stdin: stdin || undefined, timeout: timeout() });
return json({ returncode: r.code, stdout: r.stdout, stderr: r.stderr, success: r.success });
}
finally {
(0, promises_1.unlink)(tmp).catch(() => { });
}
}
if (action === "file") {
const p = (0, sandbox_1.safe)(ws(), path);
if (!await fileExists(p))
return `File not found: ${path}`;
const argv = args.trim() ? args.split(/\s+/) : [];
const r = await (0, sandbox_1.run)(await py(), [p, ...argv], { cwd: ws(), stdin: stdin || undefined, timeout: timeout() });
return json({ returncode: r.code, stdout: r.stdout, stderr: r.stderr, success: r.success });
}
if (action === "test") {
ctx.status("Running testsโฆ");
const p = (0, sandbox_1.safe)(ws(), path);
const python = await py();
const envPytest = python.replace(/\/python[^/]*$/, "/pytest");
const hasPytest = (await (0, sandbox_1.run)(envPytest, ["--version"], { timeout: 3 })).success;
const extraFlags = [...(verbose ? ["-v"] : []), ...(test_pattern ? ["-k", test_pattern] : []), ...(extra_args.trim() ? extra_args.split(/\s+/) : []), p];
const cmd = hasPytest ? envPytest : python;
const fargs = hasPytest ? extraFlags : ["-m", "pytest", ...extraFlags];
const r = await (0, sandbox_1.run)(cmd, fargs, { cwd: ws(), timeout: timeout() });
return (r.stdout + r.stderr).trim();
}
if (action === "pip_install") {
ctx.status(`Installing: ${packages}`);
if (!canPip())
return disabled("python_run:pip_install");
const pkgs = packages.trim().split(/\s+/).filter(Boolean);
if (!pkgs.length)
return "No packages specified.";
const r = await (0, sandbox_1.run)(await py(), ["-m", "pip", "install", ...(upgrade ? ["--upgrade"] : []), ...pkgs], { timeout: 180 });
return (r.stdout + r.stderr).trim();
}
if (action === "pip_list") {
const r = await (0, sandbox_1.run)(await py(), ["-m", "pip", "list", "--format", "json", ...(outdated ? ["--outdated"] : [])], { timeout: 30 });
return r.success ? r.stdout.trim() : r.stderr;
}
throw new Error(`Unknown action: ${action}`);
}),
}),
(0, sdk_1.tool)({
name: "get_environment",
description: (0, sdk_1.text) `
Return key runtime information: Python version, PATH, compiler availability,
and which development tools are installed.
`,
parameters: {},
implementation: safe_impl("get_environment", async () => {
const checks = [
"python3", "pip3", "gcc", "g++", "clang", "clang++",
"cmake", "make", "ninja", "ruff", "black", "mypy",
"pytest", "clang-format", "clang-tidy", "git",
];
const info = {};
await Promise.all(checks.map(async (t) => {
const r = await (0, sandbox_1.run)("which", [t], { timeout: 3 });
info[t] = r.success ? r.stdout.trim() : "not found";
}));
const pyVer = await (0, sandbox_1.run)(await py(), ["--version"], { timeout: 5 });
return json({
workspace: ws(),
platform: process.platform,
node: process.version,
python: pyVer.stdout.trim() || pyVer.stderr.trim(),
tools: info,
});
}),
}),
// =========================================================================
// PYTHON DEV
// =========================================================================
(0, sdk_1.tool)({
name: "python_quality",
description: (0, sdk_1.text) `
Python code-quality tools: AST analysis, formatting, linting, and type-checking.
action: "analyze" โ parse file with AST and return imports/classes/functions/globals
action: "format" โ format in-place with ruff (preferred) or black
action: "lint" โ lint with ruff or pylint, optionally auto-fix
action: "typecheck" โ run mypy type-checker
`,
parameters: {
action: zod_1.z.enum(["analyze", "format", "lint", "typecheck"]).describe("Quality operation to run"),
path: zod_1.z.string().describe("Relative path to .py file or directory"),
tool: zod_1.z.enum(["auto", "ruff", "black", "pylint", "mypy"]).default("auto").describe("format/lint: which tool to use"),
check_only: zBool(false).describe("format: report only, do not modify"),
fix: zBool(false).describe("lint: auto-fix safe violations (ruff only)"),
strict: zBool(false).describe("typecheck: enable --strict mode"),
},
implementation: safe_impl("python_quality", async ({ action, path, tool: chosenTool, check_only, fix, strict }) => {
const p = (0, sandbox_1.safe)(ws(), path);
if (!await fileExists(p))
return `Not found: ${path}`;
if (action === "analyze") {
if (!canPython())
return disabled("python_quality:analyze");
const script = `
import ast, json, sys
src = open(${JSON.stringify(p)}).read()
try:
tree = ast.parse(src, filename=${JSON.stringify(p)})
except SyntaxError as e:
print(json.dumps({"syntax_error": str(e)})); sys.exit(0)
result = {"imports": [], "classes": [], "functions": [], "globals": []}
def get_args(f):
a = f.args
pos = [f"{x.arg}/" for x in (a.posonlyargs or [])]
reg = [x.arg for x in a.args]
var = [f"*{a.vararg.arg}"] if a.vararg else []
kwo = [x.arg for x in a.kwonlyargs]
kw = [f"**{a.kwarg.arg}"] if a.kwarg else []
return pos + reg + var + kwo + kw
for node in tree.body:
if isinstance(node, (ast.Import, ast.ImportFrom)):
if isinstance(node, ast.Import):
result["imports"] += [a.asname or a.name for a in node.names]
else:
m = node.module or ""
result["imports"] += [f"{m}.{a.asname or a.name}" for a in node.names]
elif isinstance(node, ast.ClassDef):
methods = []
for item in node.body:
if isinstance(item, (ast.FunctionDef, ast.AsyncFunctionDef)):
methods.append({"name": item.name, "async": isinstance(item, ast.AsyncFunctionDef),
"args": get_args(item), "returns": ast.unparse(item.returns) if item.returns else None,
"doc": ast.get_docstring(item), "line": item.lineno})
result["classes"].append({"name": node.name,
"bases": [ast.unparse(b) for b in node.bases],
"methods": methods, "doc": ast.get_docstring(node), "line": node.lineno})
elif isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
result["functions"].append({"name": node.name, "async": isinstance(node, ast.AsyncFunctionDef),
"args": get_args(node), "returns": ast.unparse(node.returns) if node.returns else None,
"doc": ast.get_docstring(node), "line": node.lineno,
"decorators": [ast.unparse(d) for d in node.decorator_list]})
elif isinstance(node, ast.Assign):
for t in node.targets:
if isinstance(t, ast.Name): result["globals"].append(t.id)
print(json.dumps(result))
`;
const r = await (0, sandbox_1.run)(await py(), ["-c", script], { timeout: 30 });
return r.success ? r.stdout.trim() : `Analysis failed:\n${r.stderr}`;
}
if (action === "format") {
const hasRuff = (await (0, sandbox_1.run)("which", ["ruff"], { timeout: 3 })).success;
const hasBlack = (await (0, sandbox_1.run)("which", ["black"], { timeout: 3 })).success;
const useRuff = chosenTool === "auto" ? hasRuff : chosenTool === "ruff";
if (useRuff && !hasRuff)
return "ruff not found. Install with: pip install ruff";
if (!useRuff && !hasBlack)
return "black not found. Install with: pip install black";
let cmd;
let args;
if (useRuff) {
cmd = "ruff";
args = ["format", ...(check_only ? ["--check"] : []), p];
}
else {
cmd = "black";
args = [...(check_only ? ["--check"] : []), p];
}
const r = await (0, sandbox_1.run)(cmd, args, { timeout: 30 });
return (r.stdout + r.stderr).trim() || `Formatted with ${useRuff ? "ruff" : "black"}`;
}
if (action === "lint") {
const hasRuff = (await (0, sandbox_1.run)("which", ["ruff"], { timeout: 3 })).success;
const useRuff = chosenTool === "auto" ? hasRuff : chosenTool === "ruff";
let cmd;
let args;
if (useRuff) {
cmd = "ruff";
args = ["check", ...(fix ? ["--fix"] : []), "--output-format", "text", p];
}
else {
cmd = "pylint";
args = [p];
}
const r = await (0, sandbox_1.run)(cmd, args, { timeout: 60 });
return (r.stdout + r.stderr).trim() || "No issues found.";
}
if (action === "typecheck") {
const hasMypy = (await (0, sandbox_1.run)("which", ["mypy"], { timeout: 3 })).success;
if (!hasMypy)
return "mypy not found. Install with: pip install mypy";
const r = await (0, sandbox_1.run)("mypy", [...(strict ? ["--strict"] : []), p], { cwd: ws(), timeout: 120 });
return (r.stdout + r.stderr).trim() || "No type errors found.";
}
throw new Error(`Unknown action: ${action}`);
}),
}),
// =========================================================================
// C++ DEV
// =========================================================================
(0, sdk_1.tool)({
name: "cpp",
description: (0, sdk_1.text) `
C++ development tools: compile, run binaries, format, analyze, build with CMake, and get compiler info.
Compilation/run require Settings โ Allow C++ Compilation.
action: "compile" โ compile a .cpp source file (clang++ or g++)
action: "run" โ execute a compiled binary in the workspace
action: "compile_and_run" โ compile then immediately run (for quick snippets)
action: "format" โ format source file with clang-format
action: "analyze" โ run clang-tidy static analysis
action: "cmake" โ configure and build a CMake project
action: "info" โ return version strings for available C++ tools
`,
parameters: {
action: zod_1.z.enum(["compile", "run", "compile_and_run", "format", "analyze", "cmake", "info"]).describe("C++ operation"),
path: zod_1.z.string().default("").describe("compile/run/format/analyze: relative path to source or binary"),
output: zod_1.z.string().default("").describe("compile: output binary name (default: source stem)"),
standard: zod_1.z.enum(["c++11", "c++14", "c++17", "c++20", "c++23"]).default("c++17").describe("compile/compile_and_run: C++ standard"),
flags: zod_1.z.string().default("-Wall -Wextra").describe("compile/compile_and_run: extra compiler flags"),
sanitizers: zod_1.z.string().default("").describe("compile: comma-separated sanitizers (address, undefined, thread)"),
optimisation: zod_1.z.enum(["0", "1", "2", "3", "s", "fast"]).default("0").describe("compile: optimisation level"),
args: zod_1.z.string().default("").describe("run: space-separated arguments"),
stdin: zod_1.z.string().default("").describe("run/compile_and_run: text piped to stdin"),
source_or_path: zod_1.z.string().default("").describe("compile_and_run: raw C++ source code or file path"),
is_file: zBool(false).describe("compile_and_run: treat source_or_path as a file path"),
style: zod_1.z.string().default("LLVM").describe("format: clang-format style preset or 'file'"),
check_only: zBool(false).describe("format: report only, do not modify"),
checks: zod_1.z.string().default("clang-analyzer-*,bugprone-*,modernize-*,performance-*").describe("analyze: comma-separated clang-tidy check globs"),
fix: zBool(false).describe("analyze: apply auto-fixes where available"),
source_dir: zod_1.z.string().default(".").describe("cmake: directory containing CMakeLists.txt"),
build_dir: zod_1.z.string().default("build").describe("cmake: out-of-source build directory"),
cmake_args: zod_1.z.string().default("").describe("cmake: extra cmake args (e.g. '-DCMAKE_BUILD_TYPE=Release')"),
build_target: zod_1.z.string().default("").describe("cmake: specific build target (empty = default)"),
clean: zBool(false).describe("cmake: run --target clean before build"),
},
implementation: safe_impl("cpp", async ({ action, path, output, standard, flags, sanitizers, optimisation, args, stdin, source_or_path, is_file, style, check_only, checks, fix, source_dir, build_dir, cmake_args, build_target, clean }) => {
if (action === "compile") {
if (!canCpp())
return disabled("cpp:compile");
const cxx = await (0, sandbox_1.detectCxx)(preferClang());
if (!cxx)
return "No C++ compiler found. Install g++ or clang++.";
const src = (0, sandbox_1.safe)(ws(), path);
if (!await fileExists(src))
return `File not found: ${path}`;
const outName = output || (0, path_1.basename)(src, (0, path_1.extname)(src));
const outPath = (0, sandbox_1.safe)(ws(), outName);
const compArgs = [src, `-std=${standard}`, `-O${optimisation}`, "-o", outPath];
if (flags.trim())
compArgs.push(...flags.split(/\s+/));
const sanMap = {
address: "-fsanitize=address",
undefined: "-fsanitize=undefined",
thread: "-fsanitize=thread",
};
for (const s of sanitizers.split(",").map(s => s.trim()).filter(Boolean)) {
if (!sanMap[s])
return `Unknown sanitizer: '${s}'. Choose from: ${Object.keys(sanMap).join(", ")}`;
compArgs.push(sanMap[s]);
}
const r = await (0, sandbox_1.run)(cxx, compArgs, { cwd: ws(), timeout: 120 });
return json({ compiler: cxx, command: [cxx, ...compArgs].join(" "), output_binary: r.success ? (0, path_1.relative)(ws(), outPath) : null, ...r });
}
if (action === "run") {
if (!canCpp())
return disabled("cpp:run");
const p = (0, sandbox_1.safe)(ws(), path);
if (!await fileExists(p))
return `Binary not found: ${path}`;
const argv = args.trim() ? args.split(/\s+/) : [];
const r = await (0, sandbox_1.run)(p, argv, { cwd: ws(), stdin: stdin || undefined, timeout: timeout() });
return json({ returncode: r.code, stdout: r.stdout, stderr: r.stderr, success: r.success });
}
if (action === "compile_and_run") {
if (!canCpp())
return disabled("cpp:compile_and_run");
const cxx = await (0, sandbox_1.detectCxx)(preferClang());
if (!cxx)
return "No C++ compiler found.";
let srcPath;
let cleanup = false;
if (is_file) {
srcPath = (0, sandbox_1.safe)(ws(), source_or_path);
if (!await fileExists(srcPath))
return `File not found: ${source_or_path}`;
}
else {
srcPath = (0, path_1.join)((0, os_1.tmpdir)(), `lms_cpp_${Date.now()}.cpp`);
await (0, promises_1.writeFile)(srcPath, source_or_path, "utf-8");
cleanup = true;
}
const binPath = srcPath.replace(/\.cpp$/, "").replace(/\.cc$/, "") + "_bin";
try {
const compileArgs = [srcPath, `-std=${standard}`, "-O0", "-o", binPath];
if (flags.trim())
compileArgs.push(...flags.split(/\s+/));
const sanMap = {
address: "-fsanitize=address",
undefined: "-fsanitize=undefined",
thread: "-fsanitize=thread",
};
const sanList = sanitizers || "address,undefined";
for (const s of sanList.split(",").map(s => s.trim()).filter(Boolean)) {
if (sanMap[s])
compileArgs.push(sanMap[s]);
}
const comp = await (0, sandbox_1.run)(cxx, compileArgs, { timeout: 120 });
if (!comp.success)
return json({ phase: "compile", returncode: comp.code, error: comp.stderr, success: false });
const execResult = await (0, sandbox_1.run)(binPath, [], { stdin: stdin || undefined, timeout: timeout() });
return json({
compile: { returncode: comp.code, warnings: comp.stderr },
run: { returncode: execResult.code, stdout: execResult.stdout, stderr: execResult.stderr, success: execResult.success },
});
}
finally {
if (cleanup)
(0, promises_1.unlink)(srcPath).catch(() => { });
(0, promises_1.unlink)(binPath).catch(() => { });
}
}
if (action === "format") {
const hasClangFmt = (await (0, sandbox_1.run)("which", ["clang-format"], { timeout: 3 })).success;
if (!hasClangFmt)
return "clang-format not found. Install LLVM/Clang tools.";
const p = (0, sandbox_1.safe)(ws(), path);
if (!await fileExists(p))
return `Not found: ${path}`;
const fmtArgs = [`-style=${style}`, ...(check_only ? ["--dry-run", "--Werror"] : ["-i"]), p];
const r = await (0, sandbox_1.run)("clang-format", fmtArgs, { timeout: 30 });
if (check_only)
return r.success ? "Already formatted." : `Formatting needed:\n${r.stderr}`;
return r.success ? `Formatted ${(0, path_1.relative)(ws(), p)}` : `clang-format error:\n${r.stderr}`;
}
if (action === "analyze") {
const hasTidy = (await (0, sandbox_1.run)("which", ["clang-tidy"], { timeout: 3 })).success;
if (!hasTidy)
return "clang-tidy not found. Install LLVM/Clang tools.";
const p = (0, sandbox_1.safe)(ws(), path);
if (!await fileExists(p))
return `Not found: ${path}`;
const tidyArgs = [`--checks=${checks}`, ...(fix ? ["--fix"] : []), p];
const r = await (0, sandbox_1.run)("clang-tidy", tidyArgs, { cwd: ws(), timeout: 120 });
return (r.stdout + r.stderr).trim() || "No issues found by clang-tidy.";
}
if (action === "cmake") {
if (!canCpp())
return disabled("cpp:cmake");
const hasCmake = (await (0, sandbox_1.run)("which", ["cmake"], { timeout: 3 })).success;
if (!hasCmake)
return "cmake not found. Install CMake.";
const src = (0, sandbox_1.safe)(ws(), source_dir);
const bld = (0, sandbox_1.safe)(ws(), build_dir);
await (0, promises_1.mkdir)(bld, { recursive: true });
const cfgArgs = [src, "-B", bld, ...(cmake_args.trim() ? cmake_args.split(/\s+/) : [])];
const cfg = await (0, sandbox_1.run)("cmake", cfgArgs, { cwd: ws(), timeout: 120 });
if (!cfg.success)
return json({ phase: "configure", returncode: cfg.code, error: cfg.stderr, success: false });
if (clean)
await (0, sandbox_1.run)("cmake", ["--build", bld, "--target", "clean"], { timeout: 60 });
const bldArgs = ["--build", bld, "--parallel", ...(build_target ? ["--target", build_target] : [])];
const bldResult = await (0, sandbox_1.run)("cmake", bldArgs, { timeout: 300 });
return json({
configure: { returncode: cfg.code, output: cfg.stdout },
build: { returncode: bldResult.code, stdout: bldResult.stdout, stderr: bldResult.stderr, success: bldResult.success },
});
}
if (action === "info") {
const tools = ["clang++", "g++", "cmake", "make", "ninja", "clang-format", "clang-tidy", "ar"];
const info = {};
await Promise.all(tools.map(async (t) => {
const w = await (0, sandbox_1.run)("which", [t], { timeout: 3 });
if (!w.success) {
info[t] = "not found";
return;
}
const v = await (0, sandbox_1.run)(t, ["--version"], { timeout: 5 });
info[t] = (v.stdout + v.stderr).split("\n")[0].trim();
}));
return json(info);
}
throw new Error(`Unknown action: ${action}`);
}),
}),
// =========================================================================
// RESEARCH โ omitted when altra/web-search peer is loaded
// =========================================================================
...(webPeerLoaded ? [] : [(0, sdk_1.tool)({
name: "fetch_url",
description: (0, sdk_1.text) `
Fetch a web page and return its text content (HTML stripped by default).
Only public URLs (http/https) are supported โ private/internal IPs are blocked.
`,
parameters: {
url: zod_1.z.string().describe("Full URL to fetch (must start with http:// or https://)"),
raw_html: zBool(false).describe("Return raw HTML instead of plain text"),
max_chars: zInt(50000).describe("Truncate at this many characters"),
},
implementation: safe_impl("fetch_url", async ({ url, raw_html, max_chars }) => {
if (!url.startsWith("http://") && !url.startsWith("https://")) {
return "Error: URL must start with http:// or https://";
}
// Block private/link-local IPs via a quick DNS+check approach
try {
const { hostname } = new URL(url);
// Rough private IP pattern check (before DNS resolution)
const privatePatterns = [
/^localhost$/i,
/^127\./,
/^10\./,
/^172\.(1[6-9]|2\d|3[01])\./,
/^192\.168\./,
/^169\.254\./,
/^::1$/,
/^fc[0-9a-f]{2}:/i,
/^fe[89ab][0-9a-f]:/i,
];
if (privatePatterns.some(r => r.test(hostname))) {
return `Request blocked: '${hostname}' is a private/internal address`;
}
}
catch {
return "Invalid URL";
}
try {
const res = await fetch(url, {
headers: { "User-Agent": "Mozilla/5.0 (LM Studio high-perf-tools/1.0)" },
signal: AbortSignal.timeout(20_000),
});
if (!res.ok)
return `HTTP ${res.status} ${res.statusText}`;
let body = await res.text();
if (!raw_html)
body = stripHtml(body);
if (body.length > max_chars)
body = body.slice(0, max_chars) + `\n\n[... truncated at ${max_chars} chars ...]`;
return body;
}
catch (e) {
return `Fetch failed: ${e.message}`;
}
}),
}),
(0, sdk_1.tool)({
name: "search_web",
description: (0, sdk_1.text) `
Search the web with DuckDuckGo and return a list of results with titles, URLs, and snippets.
`,
parameters: {
query: zod_1.z.string().describe("Search query"),
num_results: zod_1.z.coerce.number().int().min(1).max(20).default(5).describe("Number of results"),
time_range: zod_1.z.enum(["day", "week", "month", "year", "any"]).default("any")
.describe("Limit results to a recency window. 'any' = no filter (default). Applied natively on each search engine."),
},
implementation: safe_impl("search_web", async ({ query, num_results, time_range }) => {
const tr = time_range === "any" ? undefined : time_range;
const items = await webSearch(query, num_results, tr);
return json(items);
}),
})]),
// =========================================================================
// GIT
// =========================================================================
(0, sdk_1.tool)({
name: "git",
description: (0, sdk_1.text) `
Git operations: status, diff, log, show, branches, stage, commit, init.
Write operations (stage, commit) require Settings โ Enable Git Write.
action: "status" โ show working-tree status (staged, unstaged, untracked)
action: "diff" โ show diff; set staged=true for index diff
action: "log" โ show commit history
action: "show" โ show details and diff of a specific commit
action: "branches" โ list all local and remote branches
action: "stage" โ stage files for next commit (git add); supports glob patterns
action: "commit" โ create a commit; optionally stage files first
action: "init" โ initialise a new git repository
`,
parameters: {
action: zod_1.z.enum(["status", "diff", "log", "show", "branches", "stage", "commit", "init"]).describe("Git operation"),
path: zod_1.z.string().default(".").describe("Relative path of git repository"),
staged: zBool(false).describe("diff: show staged diff instead of working-tree"),
file_path: zod_1.z.string().default("").describe("diff: restrict diff to this file"),
n: zod_1.z.coerce.number().int().min(1).max(100).default(15).describe("log: number of commits"),
oneline: zBool(true).describe("log: compact one-line format"),
author: zod_1.z.string().default("").describe("log: filter by author name/email"),
since: zod_1.z.string().default("").describe("log: show commits after this date (e.g. '2 weeks ago')"),
ref: zod_1.z.string().default("HEAD").describe("show: commit hash, tag, or branch"),
files: zod_1.z.string().default(".").describe("stage/commit: space-separated file paths or glob patterns"),
message: zod_1.z.string().default("").describe("commit: commit message"),
},
implementation: safe_impl("git", async ({ action, path, staged, file_path, n, oneline, author, since, ref, files, message }) => {
const p = (0, sandbox_1.safe)(ws(), path);
if (action === "status") {
const r = await (0, sandbox_1.run)("git", ["status", "--short", "--branch"], { cwd: p, timeout: 15 });
return r.stdout || r.stderr || "Not a git repository";
}
if (action === "diff") {
const args = ["diff", ...(staged ? ["--cached"] : []), ...(file_path.trim() ? ["--", file_path] : [])];
const r = await (0, sandbox_1.run)("git", args, { cwd: p, timeout: 30 });
return r.stdout || r.stderr || "(no diff)";
}
if (action === "log") {
const args = ["log", `-${n}`,
...(oneline ? ["--oneline"] : []),
...(author ? [`--author=${author}`] : []),
...(since ? [`--since=${since}`] : []),
];
const r = await (0, sandbox_1.run)("git", args, { cwd: p, timeout: 15 });
return r.stdout || r.stderr;
}
if (action === "show") {
if (ref.startsWith("-"))
return "Error: ref must not start with '-'";
const r = await (0, sandbox_1.run)("git", ["show", ref], { cwd: p, timeout: 15 });
return r.stdout || r.stderr;
}
if (action === "branches") {
const r = await (0, sandbox_1.run)("git", ["branch", "-a"], { cwd: p, timeout: 10 });
return r.stdout || r.stderr;
}
if (action === "stage") {
if (!canGitWrite())
return disabled("git:stage");
const patterns = files.trim().split(/\s+/).filter(Boolean);
const expanded = [];
for (const pattern of patterns) {
if (pattern.includes("*") || pattern.includes("?") || pattern.includes("{")) {
const ls = await (0, sandbox_1.run)("git", ["ls-files", "--modified", "--others", "--exclude-standard", "-z"], { cwd: p, timeout: 15 });
const tracked = await (0, sandbox_1.run)("git", ["ls-files", "-z"], { cwd: p, timeout: 15 });
const allFiles = [...new Set([...ls.stdout.split("\0"), ...tracked.stdout.split("\0")])].filter(Boolean);
const globToRegex = (g) => new RegExp("^" + g.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]") + "$");
const re = globToRegex(pattern);
const matches = allFiles.filter((f) => re.test(f));
expanded.push(...(matches.length ? matches : [pattern]));
}
else {
expanded.push(pattern);
}
}
const unique = [...new Set(expanded)];
const r = await (0, sandbox_1.run)("git", ["add", "--", ...unique], { cwd: p, timeout: 30 });
const stagedCount = unique.filter((f) => !f.includes("*")).length;
return r.stdout || r.stderr || `Staged ${stagedCount} file(s): ${unique.slice(0, 10).join(", ")}${unique.length > 10 ? `โฆ (+${unique.length - 10} more)` : ""}`;
}
if (action === "commit") {
if (!canGitWrite())
return disabled("git:commit");
if (!message.trim())
return "Error: commit message cannot be empty";
if (files.trim() && files !== ".") {
const stage = await (0, sandbox_1.run)("git", ["add", ...files.split(/\s+/).filter(Boolean)], { cwd: p, timeout: 15 });
if (!stage.success)
return `git add failed:\n${stage.stderr}`;
}
const r = await (0, sandbox_1.run)("git", ["commit", "-m", message], { cwd: p, timeout: 30 });
return r.stdout || r.stderr;
}
if (action === "init") {
await (0, promises_1.mkdir)(p, { recursive: true });
const r = await (0, sandbox_1.run)("git", ["init"], { cwd: p, timeout: 15 });
return r.stdout || r.stderr;
}
throw new Error(`Unknown action: ${action}`);
}),
}),
// =========================================================================
// AGENT ZERO โ Memory ยท Sub-agents ยท Dynamic Tools
// =========================================================================
// โโ Memory โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
(0, sdk_1.tool)({
name: "memory",
description: (0, sdk_1.text) `
Persistent memory across conversations: save, recall, list, and delete entries.
action: "save" โ save a fact or solution with a key and optional tags
action: "recall" โ search memories by keywords, optionally filtered by tags
action: "list" โ list all saved memory keys, tags, and dates
action: "delete" โ delete a memory entry by id or exact key
`,
parameters: {
action: zod_1.z.enum(["save", "recall", "list", "delete"]).describe("Memory operation"),
key: zod_1.z.string().default("").describe("save: short title / identifier for this memory"),
content: zod_1.z.string().default("").describe("save: full content to remember"),
tags: zod_1.z.string().default("").describe("save/recall/list: comma-separated tags"),
query: zod_1.z.string().default("").describe("recall: keywords to search for"),
limit: zInt(5).describe("recall: maximum results to return"),
id_or_key: zod_1.z.string().default("").describe("delete: memory id or exact key to delete"),
},
implementation: safe_impl("memory", async ({ action, key, content, tags, query, limit, id_or_key }) => {
const tagList = tags.split(",").map(t => t.trim()).filter(Boolean);
if (action === "save")
return (0, memory_1.memorySave)(ws(), key, content, tagList);
if (action === "recall")
return (0, memory_1.memoryRecall)(ws(), query, limit, tagList);
if (action === "list")
return (0, memory_1.memoryList)(ws(), tagList);
if (action === "delete")
return (0, memory_1.memoryDelete)(ws(), id_or_key);
throw new Error(`Unknown action: ${action}`);
}),
}),
// โโ Sub-agents โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
(0, sdk_1.tool)({
name: "list_models",
description: (0, sdk_1.text) `
List all models currently loaded in LM Studio.
Use this before spawn_agent to see what models are available.
On low-RAM devices only one model will typically be shown.
`,
parameters: {},
implementation: safe_impl("list_models", async () => {
const endpoint = cfg.get("lmStudioEndpoint");
const models = await (0, subagent_1.listLoadedModels)(cfg.get("lmStudioEndpoint"), cfg.get("lmStudioApiKey"));
if (!models.length)
return "No models currently loaded in LM Studio.";
return json({
loaded_models: models,
note: models.length === 1
? "Only one model loaded. spawn_agent will reuse it (no extra RAM required)."
: `${models.length} models loaded. spawn_agent can use a dedicated sub-agent model.`,
});
}),
}),
(0, sdk_1.tool)({
name: "spawn_agent",
description: (0, sdk_1.text) `
Spawn a sub-agent to handle a specific task autonomously.
RAM behaviour:
โข If only one model is loaded (low-RAM device) โ the same model is reused
with a different system prompt. No extra RAM consumed.
โข If a Sub-Agent Model ID is configured in settings AND that model is loaded
โ it is used as the dedicated sub-agent.
The sub-agent has access to: read_file, write_file, list_directory,
run_python_code, run_command, memory_save, memory_recall.
Set allow_tools=false for a simple one-shot generation (faster, less RAM).
`,
parameters: {
task: zod_1.z.string().describe("The task to delegate to the sub-agent"),
context: zod_1.z.string().default("").describe("Optional background context to provide"),
system_role: zod_1.z.string().default("").describe("Custom system prompt for the sub-agent (blank = sensible default)"),
allow_tools: zBool(true).describe("Whether the sub-agent can use tools (set false for pure generation tasks)"),
},
implementation: safe_impl("spawn_agent", async ({ task, context, system_role, allow_tools }) => {
const toolCtx = {
workspace: ws(),
pythonBin: await py(),
timeout: timeout(),
};
return (0, subagent_1.spawnAgent)({
endpoint: cfg.get("lmStudioEndpoint"),
preferredModelId: cfg.get("subAgentModelId"),
maxIterations: cfg.get("subAgentMaxIterations"),
systemPrompt: system_role,
task,
context,
toolCtx,
allowTools: allow_tools,
lmStudioApiKey: cfg.get("lmStudioApiKey"),
});
}),
}),
// โโ Dynamic tools โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
(0, sdk_1.tool)({
name: "custom_tool",
description: (0, sdk_1.text) `
Manage reusable Python tools that persist across conversations.
action: "create" โ create a new tool (python_code body receives 'args: dict', returns a value)
action: "call" โ call a previously created tool by name with JSON args
action: "list" โ list all created tools with descriptions and argument schemas
action: "delete" โ delete a tool by name
Example python_code for create:
result = args.get("x", 0) + args.get("y", 0)
return str(result)
`,
parameters: {
action: zod_1.z.enum(["create", "call", "list", "delete"]).describe("Custom tool operation"),
name: zod_1.z.string().default("").describe("create/call/delete: tool name (alphanumeric + underscores)"),
description: zod_1.z.string().default("").describe("create: what this tool does"),
args_schema: zod_1.z.string().default("").describe("create: description of expected JSON args (free text)"),
python_code: zod_1.z.string().default("").describe("create: Python function body"),
args_json: zod_1.z.string().default("{}").describe("call: JSON object of arguments"),
},
implementation: safe_impl("custom_tool", async ({ action, name, description, args_schema, python_code, args_json }) => {
if (action === "create")
return (0, dynamicTools_1.createTool)(ws(), name, description, args_schema, python_code);
if (action === "call")
return (0, dynamicTools_1.callTool)(ws(), name, args_json, await py(), timeout());
if (action === "list")
return (0, dynamicTools_1.listTools)(ws());
if (action === "delete")
return (0, dynamicTools_1.deleteTool)(ws(), name);
throw new Error(`Unknown action: ${action}`);
}),
}),
];
return tools;
};
exports.toolsProvider = toolsProvider;