src / promptPreprocessor.ts
import type { ChatMessage, PromptPreprocessorController } from "@lmstudio/sdk";
import { configSchematics } from "./config";
import { searchMemories } from "./store";
const MIN_QUERY_LENGTH = 3;
export async function preprocess(ctl: PromptPreprocessorController, userMessage: ChatMessage) {
const pluginConfig = ctl.getPluginConfig(configSchematics);
const injectionEnabled = pluginConfig.get("memoryInjectionEnabled");
const retrievalLimit = pluginConfig.get("retrievalLimit");
const userPrompt = userMessage.getText();
if (!injectionEnabled || userPrompt.trim().length < MIN_QUERY_LENGTH) {
return userMessage;
}
const status = ctl.createStatus({
status: "loading",
text: "Checking Alexiel's memory for relevant context...",
});
let matches;
try {
matches = searchMemories(userPrompt, retrievalLimit);
} catch (error) {
ctl.debug("Memory search failed", error);
status.setState({ status: "canceled", text: "Memory search failed, continuing without it." });
return userMessage;
}
if (matches.length === 0) {
status.setState({ status: "canceled", text: "No relevant memories found." });
return userMessage;
}
status.setState({
status: "done",
text: `Found ${matches.length} relevant ${matches.length === 1 ? "memory" : "memories"}.`,
});
ctl.debug("Injected memories", matches);
const memoryBlock = matches
.map((m) => `[${m.key}]${m.tags ? ` (${m.tags})` : ""}\n${m.content}`)
.join("\n\n");
const processedContent =
`The following are things you (Alexiel) have previously remembered that may be relevant ` +
`to this message. Use them only if they're actually relevant — don't force a connection:\n\n` +
`${memoryBlock}\n\n---\n\nUser message:\n\n${userPrompt}`;
return processedContent;
}