Forked from tupik/doit
src / toolsProvider.ts
import { tool, type ToolsProviderController } from "@lmstudio/sdk";
import { z } from "zod";
import * as fs from "fs";
import * as path from "path";
async function toolsProvider(ctl: ToolsProviderController) {
const do_tools: any[] = [];
// -1
const getDateTimeTool = tool({
name: "get_date_time",
description: "Returns current date and time. Use only on explicit time request.",
parameters: {},
implementation: async () => {
return new Date().toISOString();
}
});
do_tools.push(getDateTimeTool);
//--2
const CWTool = tool({
name: "count_letters",
description: "Counts occurrences of a character in a string.",
parameters: {
word: z.string(),
letr: z.string().length(1)
},
implementation: async ({ word, letr }) => {
return [...word].filter(c => c === letr).length;
}
});
do_tools.push(CWTool);
//--3
const getLengthTool = tool({
name: "get_word_length",
description: "Returns the length of the input string.",
parameters: {
word: z.string()
},
implementation: async ({ word }) => {
return { length: word.length };
}
});
do_tools.push(getLengthTool);
//--4
const getMyIPTool = tool({
name: "get_myip",
description: "Returns user's public IP address. Test internet connection.",
parameters: {},
implementation: async () => {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 2000);
try {
const response = await fetch("https://ifconfig.me/ip", {
signal: controller.signal
});
clearTimeout(timeoutId);
const ip = (await response.text()).trim();
return { ip };
} catch (error) {
clearTimeout(timeoutId);
const controller2 = new AbortController();
const timeoutId2 = setTimeout(() => controller2.abort(), 2000);
try {
const response = await fetch("https://api.country.is/", {
signal: controller2.signal
});
clearTimeout(timeoutId2);
const ip = (await response.text()).trim();
return ip;
} catch (error) {
clearTimeout(timeoutId2);
return { ip: null, error: "No response from 2 servers" };
}
}
}
});
do_tools.push(getMyIPTool);
//--5
const getAnagramTool = tool({
name: "get_anagram",
description: "Returns anagram of the input string/word.",
parameters: {
word: z.string().describe("Input word")
},
implementation: async (params) => {
const w = params.word;
const c = [...w];
const crypto = await import('crypto');
//const { randomInt } = await import('crypto'); |\_ _ _ _ _just_option____
//const j = randomInt(0, i + 1); |/
console.log(`Input W: "${w}", length W: ${w.length}`);
console.log(`Input C: "${c}", length C: ${c.length}`);
console.log(`Bytes: ${c.map(x => x.codePointAt(0))}`);
for (let i = c.length - 1; i > 0; i--) {
const j = crypto.randomInt(0, i +1); //
[c[i], c[j]] = [c[j], c[i]]; //xchg letters - (Fisher-Yates shuffle)
console.log(`${i}:${j} C: "${c}", length: "${c.length}"`);
}
console.log(`result C: ${c.join("")}`);
const result = c.join('');
// Validity of result
const inputSorted = [...w].sort().join('');
const outputSorted = [...result].sort().join('');
if (inputSorted !== outputSorted) {
throw new Error(`Anagram validation failed: ${inputSorted} !== ${outputSorted}`);
}
return { anagram: result };
}
});
do_tools.push(getAnagramTool);
//--6
// Unix timestamp -> date time
const getTSD = tool({
name: "ts_to_date",
description: "Returns full date-time of input Unix ts/timestamp.",
parameters: {
ts: z.number().describe("Numeric value required for conversion")
},
implementation: async (params) => {
// Date = Unix timestamp
const pts = params.ts;
const date = new Date(pts);
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, '0'); //+1: month' from zero
const year = date.getFullYear();
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
// day of week & month
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const months = ['January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'];
const dayName = days[date.getDay()];
const monthName = months[date.getMonth()];
// Full date: "Friday, 13 June 2025, 14:30:45"
const fullDate = `${dayName}, ${day} ${monthName} ${year}, ${hours}:${minutes}:${seconds}`;
return { fullDate: fullDate };
}
});
do_tools.push(getTSD); //push tool 6 to provider
//--7
// Artifacts type="plugins" -> urls + date of updated
const getAPIv1 = tool({
name: "keep_it_secret", //keep it safe
description: "Returns only urls of plugins sorted by date-time (fresh new). A typical use case is to get list of plugins for the last week (1) and top 30. Second param cuts output. Uses artifacts from LM Studio API/v1 filtered. Don't run several in a row. Just once.",
parameters: {
//arts: z.array(z.any()).describe("Artifacts array of jsons.")
weeks: z.number().optional().describe("Numeric value of weeks that have passed before up the moment."),
top: z.number().optional().describe("Number of elements truncated to the bound")
}, // 10 weeks maximum
implementation: async ({ weeks = 10, top = undefined }: { weeks?: number, top?: number }) => {
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
const response = await fetch("https://lmstudio.ai/api/v1/artifacts",
{signal: controller.signal,
headers: { "User-Agent": "LMStudio-Plugin/1.0" }
});
clearTimeout(timeoutId);
if (!response.ok) { throw new Error(`Error in LM Studio API resp: ${response.status}`); }
const data = await response.json();
let artifacts = Array.isArray(data) ? data : data.publicArtifacts;
if (!Array.isArray(artifacts)) {
console.error("[Plugin] No array, Keys:", Object.keys(data));
return { urls: [] };
}
const msInWeek = 7 * 24 * 60 * 60 * 1000; // 1 week
const cutoff = weeks ? Date.now() - (weeks * msInWeek) : 0; //cut point. 0 is all
const result = artifacts //Result
.filter(a =>
a.type === "plugin" && // plugins only
a.forkedFromArtifactIdentifier === null && // only not forked (original)
a.url && //urls bang-on
new Date(a.updatedAt).getTime() > cutoff //date above cut point
)
.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime())
.slice(0, top)
//.map(a => a.url); //just urls
.map(a => ({
url: a.url,
updated: new Date(a.updatedAt).toISOString().split('T')[0] // urls & dates
}));
return { urls: result }; //KISS returns urls
} catch (e) {
console.error("Plugin Error:", e instanceof Error ? e.message : e);
return { urls: [], error: e instanceof Error ? e.message : String(e) };
}
}
});
do_tools.push(getAPIv1); //push tool 7 to provider
//--
return do_tools;
}
export { toolsProvider };
//end.