src / toolsProvider.ts
import { text, tool, type ToolsProviderController } from "@lmstudio/sdk";
import { z } from "zod";
// Safe alphabets - exclude easily confused characters:
// - Lowercase: no 'l' (looks like '1' or 'I')
// - Uppercase: no 'I' (looks like '1' or 'l'), no 'O' (looks like '0')
// - Numbers: no '1' (looks like 'I' or 'l'), no '0' (looks like 'O')
const SAFE_LOWERCASE = "abcdefghijkmnopqrstuvwxyz"; // 23 chars (no 'l')
const SAFE_UPPERCASE = "ABCDEFGHJKLMNPQRSTUVWXYZ"; // 24 chars (no 'I', no 'O')
const SAFE_NUMBERS = "23456789"; // 8 chars (no '0', no '1')
const SAFE_SPECIAL = "!@#$%^&*()_+-=[]{}|;:,.<>?"; // 24 chars
export async function toolsProvider(_ctl: ToolsProviderController) {
const generatePasswordTool = tool({
name: "generate_password",
description: text`
Generates cryptographically secure passwords with customizable character sets. At least one must be enabled. Safe alphabets avoid confusing characters. Default length=12, all sets on.",
`,
parameters: {
length: z.number().int().min(4).max(64).default(12).describe("Password length, min:4, max:64, default: 12 characters."),
Lowercase: z.boolean().default(true).describe("Enabled lowercase letters"),
Uppercase: z
.boolean()
.default(true)
.describe("Enabled uppercase letters"),
Numbers: z.boolean().default(true).describe("Enabled numbers, excludes '0', '1'"),
SpecialChars: z.boolean().default(true).describe("Enabled special characters"),
},
implementation: async ({ length, Lowercase, Uppercase, Numbers, SpecialChars }) => {
// Build charset from enabled character sets
let charset = "";
if (Lowercase) charset += SAFE_LOWERCASE;
if (Uppercase) charset += SAFE_UPPERCASE;
if (Numbers) charset += SAFE_NUMBERS;
if (SpecialChars) charset += SAFE_SPECIAL;
// Ensure at least one character set is enabled
if (charset.length === 0) {
throw new Error(
"At least one character set must be enabled (Lowercase, Uppercase, Numbers, or SpecialChars)"
);
}
let password = "";
const crypto = await import("crypto");
for (let i = 0; i < length; i++) {
const randomIndex = crypto.randomInt(0, charset.length);
password += charset[randomIndex];
}
return {
password,
length: password.length,
options: {
Lowercase,
Uppercase,
Numbers,
SpecialChars,
},
};
},
});
return [generatePasswordTool];
}