Project Files
src / index.ts
// src/index.ts
import { setGlobalDispatcher, Agent } from "undici";
import { type PluginContext } from "@lmstudio/sdk";
// Undici's default bodyTimeout is 300 s. Long prompt-processing phases exceed
// that before the first streaming token arrives, causing UND_ERR_BODY_TIMEOUT.
// Setting bodyTimeout: 0 removes the limit for all outgoing fetch() calls.
setGlobalDispatcher(new Agent({ bodyTimeout: 0, headersTimeout: 0 }));
import { toolsProvider } from "./toolsProvider.js";
import {
defaultPluginSettings,
configSchematics,
globalConfigSchematics,
} from "./config.js";
import { preprocess } from "./promptPreprocessor.js";
import {
getLogsDir,
} from "./core-bundle.mjs";
import { generate } from "./orchestrator.js";
import { getGlobalConfigFieldDirect } from "./helpers/globalConfigReader.js";
import { ensureUserDocsVisionPrimer } from "./helpers/visionCapabilityPrimer.js";
import fs from "fs";
import path from "path";
export async function main(context: PluginContext) {
// Register schematics first so getGlobalConfig() can access defaults
context
.withConfigSchematics(configSchematics)
.withGlobalConfigSchematics(globalConfigSchematics)
.withPromptPreprocessor(preprocess)
.withGenerator(generate)
.withToolsProvider(toolsProvider);
// Vision Capability Primer:
// main() has no SDK chat context yet, so the helper uses the central LM Studio
// chat resolver and validates the guessed conversation via pluginIdentifier.
await ensureUserDocsVisionPrimer({
baseUrl: String(getGlobalConfigFieldDirect("baseUrl") || defaultPluginSettings.baseUrl),
apiKey: String(getGlobalConfigFieldDirect("apiKey") || defaultPluginSettings.apiKey),
embeddingBaseUrl: String(
getGlobalConfigFieldDirect("embeddingBaseUrl") || defaultPluginSettings.embeddingBaseUrl
),
qwen3VlModelPath: String(
getGlobalConfigFieldDirect("qwen3VlModelPath") || defaultPluginSettings.qwen3VlModelPath
),
});
// Startup file log for diagnostics
try {
const cwd = process.cwd();
const logsDir = getLogsDir();
const ts = () => {
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();
}
};
if (!fs.existsSync(logsDir)) fs.mkdirSync(logsDir, { recursive: true });
const lines = [
`${ts()} - Plugin start`,
` cwd=${cwd}`,
` node=${process.version} platform=${process.platform} arch=${process.arch}`,
];
fs.appendFileSync(
path.join(logsDir, "user-docs-plugin.log"),
lines.join("\n") + "\n"
);
} catch {}
}