src / promptPreprocessor.ts
import { type ChatMessage, type PromptPreprocessorController } from "@lmstudio/sdk";
import { execSync } from "child_process";
// PromptPreprocessorController has no getPluginConfig.
// Clipboard injection uses a fixed 8000-char cap (mirrors config default).
// To disable: remove context.withPromptPreprocessor in index.ts and rebuild.
const MAX_CLIPBOARD_CHARS = 8000;
export async function promptPreprocessor(
ctl: PromptPreprocessorController,
userMessage: ChatMessage,
): Promise<string | ChatMessage> {
// Only inject on first message of a session
const history = await ctl.pullHistory();
if (history.length !== 0) return userMessage;
if (process.platform !== "darwin") return userMessage;
try {
let clip = execSync("pbpaste", { timeout: 3000, encoding: "utf-8" }).trim();
if (!clip) return userMessage;
if (clip.length > MAX_CLIPBOARD_CHARS) {
clip = clip.slice(0, MAX_CLIPBOARD_CHARS) + " [truncated]";
}
const injection = `[Clipboard contents:\n${clip}\n]`;
return `${injection}\n\n${userMessage.getText()}`;
} catch {
return userMessage;
}
}