Project Files
src / toolsProvider.ts
// src/toolsProvider.ts
import { type Tool, type ToolsProviderController } from "@lmstudio/sdk";
import { createGenerateImageTool } from "./tools/generate_image.js";
import { createReviewImageTool, globalConfigSchematics, getLogsDir } from "./core-bundle.mjs";
import { createReviewSequenceTool } from "./tools/review_sequence.js";
import {
checkCustomConfigs,
loadCustomConfigs,
} from "./services/customConfigsLoader.js";
import fs from "fs";
import path from "path";
// ensure consistent timestamp with timezone across logs
function localTimestamp(): string {
try {
return new Date().toLocaleString(undefined, {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false,
timeZoneName: "short",
});
} catch {
return new Date().toString();
}
}
let lastConfigSnapshotKey: string | null = null;
export async function toolsProvider(ctl: ToolsProviderController) {
// Export selected config values to process.env so underlying services can read them.
try {
const getter: any =
(ctl as any).getGlobalPluginConfig || (ctl as any).getGlobalConfig;
const gcfg = getter ? getter.call(ctl, globalConfigSchematics) : null;
const preview = gcfg.get("PREVIEW_IN_CHAT");
const httpPort = gcfg.get("HTTP_SERVER_PORT");
// Draw Things backend connection settings
const dtHost = gcfg.get("DRAW_THINGS_HOST");
const dtHttpPort = gcfg.get("DRAW_THINGS_HTTP_PORT");
const dtGrpcPort = gcfg.get("DRAW_THINGS_GRPC_PORT");
if (typeof preview === "boolean") {
process.env.PREVIEW_IN_CHAT = preview ? "true" : "false";
}
const unloadEnabled = gcfg.get("unloadAgentModelDuringRender");
if (typeof unloadEnabled === "boolean") {
process.env.UNLOAD_AGENT_MODEL_DURING_RENDER = unloadEnabled ? "true" : "false";
}
if (
typeof httpPort === "number" &&
Number.isFinite(httpPort) &&
httpPort > 0
) {
process.env.HTTP_SERVER_PORT = String(Math.floor(httpPort));
}
// Export Draw Things connection settings
if (typeof dtHost === "string" && dtHost.trim()) {
process.env.DRAW_THINGS_HOST = dtHost.trim();
}
if (
typeof dtHttpPort === "number" &&
Number.isFinite(dtHttpPort) &&
dtHttpPort > 0
) {
process.env.DRAW_THINGS_HTTP_PORT = String(Math.floor(dtHttpPort));
}
if (
typeof dtGrpcPort === "number" &&
Number.isFinite(dtGrpcPort) &&
dtGrpcPort > 0
) {
process.env.DRAW_THINGS_GRPC_PORT = String(Math.floor(dtGrpcPort));
}
// Write a config snapshot once per process to avoid burst logging
try {
if (process.env.LMS_CFG_SNAPSHOT_LOGGED !== "1") {
const logsDir = getLogsDir();
if (!fs.existsSync(logsDir)) fs.mkdirSync(logsDir, { recursive: true });
const snapshot = {
PREVIEW_IN_CHAT: process.env.PREVIEW_IN_CHAT,
UNLOAD_AGENT_MODEL_DURING_RENDER: process.env.UNLOAD_AGENT_MODEL_DURING_RENDER,
HTTP_SERVER_PORT: process.env.HTTP_SERVER_PORT,
DRAW_THINGS_HOST: process.env.DRAW_THINGS_HOST,
DRAW_THINGS_HTTP_PORT: process.env.DRAW_THINGS_HTTP_PORT,
DRAW_THINGS_GRPC_PORT: process.env.DRAW_THINGS_GRPC_PORT,
};
const key = JSON.stringify(snapshot);
lastConfigSnapshotKey = key;
const line = `${localTimestamp()} - Config snapshot: ${key}\n`;
fs.appendFileSync(
path.join(logsDir, "generate-image-plugin.log"),
line
);
process.env.LMS_CFG_SNAPSHOT_LOGGED = "1";
// Persist connection config for next startup (so warmup uses correct host/port)
try {
const connectionCache = {
DRAW_THINGS_HOST: process.env.DRAW_THINGS_HOST,
DRAW_THINGS_HTTP_PORT: process.env.DRAW_THINGS_HTTP_PORT,
DRAW_THINGS_GRPC_PORT: process.env.DRAW_THINGS_GRPC_PORT,
};
fs.writeFileSync(
path.join(logsDir, "last-connection-config.json"),
JSON.stringify(connectionCache, null, 2)
);
} catch {}
// Custom Configs: Load from config path (once per process)
try {
const customPath = gcfg.get("customConfigsPath");
// "none" or empty string disables the feature
if (
typeof customPath === "string" &&
customPath.trim() &&
customPath.trim().toLowerCase() !== "none"
) {
const status = await checkCustomConfigs(customPath);
if (status.available) {
fs.appendFileSync(
path.join(logsDir, "generate-image-plugin.log"),
`${localTimestamp()} - Custom Configs: found at ${
status.filePath
}\n`
);
const presets = await loadCustomConfigs();
fs.appendFileSync(
path.join(logsDir, "generate-image-plugin.log"),
`${localTimestamp()} - Custom Configs: loaded ${
presets.size
} presets\n`
);
} else {
fs.appendFileSync(
path.join(logsDir, "generate-image-plugin.log"),
`${localTimestamp()} - Custom Configs: not available (${
status.error || "custom_configs.json not found"
})\n`
);
}
} else {
fs.appendFileSync(
path.join(logsDir, "generate-image-plugin.log"),
`${localTimestamp()} - Custom Configs: disabled\n`
);
}
} catch (e) {
fs.appendFileSync(
path.join(logsDir, "generate-image-plugin.log"),
`${localTimestamp()} - Custom Configs: error loading: ${String(
(e as any)?.message || e
)}\n`
);
}
}
} catch {}
} catch {}
const tools: Tool[] = [];
tools.push(createGenerateImageTool(ctl));
tools.push(createReviewImageTool(ctl));
tools.push(createReviewSequenceTool(ctl));
return tools;
}