dist / toolsProvider.js
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.toolsProvider = toolsProvider;
const sdk_1 = require("@lmstudio/sdk");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const zod_1 = require("zod");
const XLSX = __importStar(require("xlsx"));
// ─── Helpers ─────────────────────────────────────────────────────────────────
function loadWorkbook(filePath) {
const ext = path.extname(filePath).toLowerCase();
if (ext === ".csv" || ext === ".tsv") {
const raw = fs.readFileSync(filePath, "utf-8");
return XLSX.read(raw, { type: "string" });
}
return XLSX.readFile(filePath);
}
function applyBoldHeader(ws) {
const range = XLSX.utils.decode_range(ws["!ref"] ?? "A1");
for (let c = range.s.c; c <= range.e.c; c++) {
const addr = XLSX.utils.encode_cell({ r: 0, c });
if (!ws[addr])
continue;
ws[addr].s = { font: { bold: true } };
}
}
function autoWidth(ws, data) {
if (!data.length)
return;
const headers = Object.keys(data[0]);
ws["!cols"] = headers.map((h) => {
const maxLen = Math.max(h.length, ...data.map((r) => String(r[h] ?? "").length));
return { wch: Math.min(maxLen + 2, 50) };
});
}
// ─── Tools provider ───────────────────────────────────────────────────────────
// Returns tools array — LM Studio calls this function and uses the return value
async function toolsProvider(_ctl) {
const tools = [];
// ── 1. xlsx_read ──────────────────────────────────────────────────────────
tools.push((0, sdk_1.tool)({
name: "xlsx_read",
description: "Read rows from an Excel (.xlsx), CSV, or TSV file. Returns JSON with column names and row data.",
parameters: {
filePath: zod_1.z.string().describe("Absolute path to the .xlsx / .csv / .tsv file"),
sheet: zod_1.z.string().optional().describe("Sheet name (default: first sheet)"),
maxRows: zod_1.z.number().optional().describe("Max rows to return (default: 100)"),
},
implementation: async ({ filePath, sheet, maxRows }) => {
try {
if (!fs.existsSync(filePath))
return `Error: File not found at "${filePath}"`;
const wb = loadWorkbook(filePath);
const sheetName = sheet ?? wb.SheetNames[0];
if (!wb.SheetNames.includes(sheetName))
return `Error: Sheet "${sheetName}" not found. Available: ${wb.SheetNames.join(", ")}`;
const ws = wb.Sheets[sheetName];
const allRows = XLSX.utils.sheet_to_json(ws, { defval: null });
const rows = allRows.slice(0, maxRows ?? 100);
return JSON.stringify({
file: filePath, sheet: sheetName,
total_rows: allRows.length, returned_rows: rows.length,
columns: rows.length > 0 ? Object.keys(rows[0]) : [],
data: rows,
}, null, 2);
}
catch (e) {
return `Error: ${String(e)}`;
}
},
}));
// ── 2. xlsx_write ─────────────────────────────────────────────────────────
tools.push((0, sdk_1.tool)({
name: "xlsx_write",
description: "Create a new Excel (.xlsx) file from an array of row objects. Applies bold headers and auto-sized columns.",
parameters: {
filePath: zod_1.z.string().describe("Absolute output path for the .xlsx file"),
data: zod_1.z.array(zod_1.z.record(zod_1.z.union([zod_1.z.string(), zod_1.z.number(), zod_1.z.null()]))).describe("Array of row objects — keys become column headers"),
sheetName: zod_1.z.string().optional().describe("Sheet name (default: Sheet1)"),
boldHeaders: zod_1.z.boolean().optional().describe("Bold headers (default: true)"),
autoWidthCols: zod_1.z.boolean().optional().describe("Auto-size columns (default: true)"),
},
implementation: async ({ filePath, data, sheetName, boldHeaders, autoWidthCols }) => {
try {
const name = sheetName ?? "Sheet1";
const wb = XLSX.utils.book_new();
const ws = XLSX.utils.json_to_sheet(data);
if (boldHeaders !== false)
applyBoldHeader(ws);
if (autoWidthCols !== false)
autoWidth(ws, data);
XLSX.utils.book_append_sheet(wb, ws, name);
const dir = path.dirname(filePath);
if (!fs.existsSync(dir))
fs.mkdirSync(dir, { recursive: true });
XLSX.writeFile(wb, filePath);
return JSON.stringify({
success: true, file: filePath, sheet: name,
rows_written: data.length,
columns: data.length > 0 ? Object.keys(data[0]) : [],
});
}
catch (e) {
return `Error: ${String(e)}`;
}
},
}));
// ── 3. xlsx_append_rows ───────────────────────────────────────────────────
tools.push((0, sdk_1.tool)({
name: "xlsx_append_rows",
description: "Append rows to an existing Excel sheet without touching other sheets.",
parameters: {
filePath: zod_1.z.string().describe("Path to existing .xlsx file"),
rows: zod_1.z.array(zod_1.z.record(zod_1.z.union([zod_1.z.string(), zod_1.z.number(), zod_1.z.null()]))).describe("Rows to append"),
sheet: zod_1.z.string().optional().describe("Sheet to append to (default: first sheet)"),
},
implementation: async ({ filePath, rows, sheet }) => {
try {
if (!fs.existsSync(filePath))
return `Error: File not found at "${filePath}"`;
const wb = XLSX.readFile(filePath);
const sheetName = sheet ?? wb.SheetNames[0];
const ws = wb.Sheets[sheetName];
const existing = XLSX.utils.sheet_to_json(ws);
const updated = [...existing, ...rows];
const newWs = XLSX.utils.json_to_sheet(updated);
autoWidth(newWs, updated);
wb.Sheets[sheetName] = newWs;
XLSX.writeFile(wb, filePath);
return JSON.stringify({
success: true, file: filePath, sheet: sheetName,
rows_before: existing.length, rows_appended: rows.length, total_rows: updated.length,
});
}
catch (e) {
return `Error: ${String(e)}`;
}
},
}));
// ── 4. xlsx_list_sheets ───────────────────────────────────────────────────
tools.push((0, sdk_1.tool)({
name: "xlsx_list_sheets",
description: "List all sheet names in an Excel workbook along with row counts and cell ranges.",
parameters: {
filePath: zod_1.z.string().describe("Path to an .xlsx file"),
},
implementation: async ({ filePath }) => {
try {
if (!fs.existsSync(filePath))
return `Error: File not found at "${filePath}"`;
const wb = loadWorkbook(filePath);
const info = wb.SheetNames.map((name) => {
const ws = wb.Sheets[name];
return { name, rows: XLSX.utils.sheet_to_json(ws).length, range: ws["!ref"] ?? "empty" };
});
return JSON.stringify({ file: filePath, sheets: info }, null, 2);
}
catch (e) {
return `Error: ${String(e)}`;
}
},
}));
// ── 5. xlsx_summarize ─────────────────────────────────────────────────────
tools.push((0, sdk_1.tool)({
name: "xlsx_summarize",
description: "Statistical summary of an Excel or CSV sheet: min, max, average, sum, unique values, null counts per column.",
parameters: {
filePath: zod_1.z.string().describe("Path to the .xlsx / .csv file"),
sheet: zod_1.z.string().optional().describe("Sheet name (default: first sheet)"),
},
implementation: async ({ filePath, sheet }) => {
try {
if (!fs.existsSync(filePath))
return `Error: File not found at "${filePath}"`;
const wb = loadWorkbook(filePath);
const sheetName = sheet ?? wb.SheetNames[0];
const ws = wb.Sheets[sheetName];
const rows = XLSX.utils.sheet_to_json(ws, { defval: null });
if (!rows.length)
return JSON.stringify({ file: filePath, empty: true });
const headers = Object.keys(rows[0]);
const stats = {};
for (const col of headers) {
const values = rows.map((r) => r[col]).filter((v) => v !== null && v !== "");
const nums = values.filter((v) => typeof v === "number");
if (nums.length > 0) {
const sum = nums.reduce((a, b) => a + b, 0);
stats[col] = {
type: "numeric", count: nums.length, nulls: rows.length - nums.length,
min: Math.min(...nums), max: Math.max(...nums),
avg: +(sum / nums.length).toFixed(4), sum: +sum.toFixed(4),
};
}
else {
const unique = new Set(values.map(String));
stats[col] = {
type: "text", count: values.length, nulls: rows.length - values.length,
unique_values: unique.size, sample: [...unique].slice(0, 5),
};
}
}
return JSON.stringify({
file: filePath, sheet: sheetName,
total_rows: rows.length, total_columns: headers.length,
column_stats: stats,
}, null, 2);
}
catch (e) {
return `Error: ${String(e)}`;
}
},
}));
return tools;
}
//# sourceMappingURL=toolsProvider.js.map