src / promptPreprocessor.ts
import { type PromptPreprocessorController, type ChatMessage } from "@lmstudio/sdk";
import { getWorkspaceDir } from "./utils.js";
const HEADER = `[nano-fs: workspace={{WORKSPACE_DIR}}]
Tools: write_file, read_file, edit_file, list_dir, make_dir, delete_path, run_bash, run_python, plan_manager, audit_plan, subagent_task.`;
export async function promptPreprocessor(
ctl: PromptPreprocessorController,
userMessage: ChatMessage
): Promise<string | ChatMessage> {
const userText = typeof userMessage.getText === "function" ? userMessage.getText() : String(userMessage);
const trimmed = userText.trim();
const workspaceDir = getWorkspaceDir();
const header = HEADER.replace("{{WORKSPACE_DIR}}", workspaceDir);
let isFirst = false;
try {
const history = await ctl.pullHistory();
if (Array.isArray(history)) {
isFirst = history.length === 0;
} else if (history && typeof history === "object" && "messages" in (history as any)) {
isFirst = (history as any).messages.length === 0;
} else {
isFirst = true;
}
} catch {
isFirst = true;
}
// 1. /plan
if (/^\/plan(\s+.*)?$/i.test(trimmed)) {
const topic = trimmed.replace(/^\/plan\s*/i, "").trim();
const prompt = `${header}
[MODO /plan]: Diseña plan conciso para: "${topic || "proyecto"}".
1. Guarda tareas en plan.md con \`plan_manager(action="create", tasks=[...])\`.
2. Muestra resumen con checkboxes [ ]. Informa que se puede ejecutar con \`/goal\`.`;
return `${prompt}\n\n${userText}`;
}
// 2. /goal
if (/^\/goal(\s+.*)?$/i.test(trimmed)) {
const objective = trimmed.replace(/^\/goal\s*/i, "").trim();
const prompt = `${header}
[MODO /goal]: Ejecución continua sin parar para: "${objective || "completar plan"}".
1. Si no hay plan, créalo con plan_manager.
2. Ejecuta tareas paso a paso con write_file/edit_file/run_bash.
3. Delega subtareas pesadas/revisiones con subagent_task (offload a GPU secundaria AMD eGPU o Intel Arc).
4. Actualiza progreso con plan_manager(action="update_task").
5. REVISIÓN: Ejecuta audit_plan(files_to_check=[...]) al terminar y confirma PASSED.`;
return `${prompt}\n\n${userText}`;
}
// 3. /review o /audit
if (/^\/(review|audit)(\s+.*)?$/i.test(trimmed)) {
const prompt = `${header}
[MODO /review]: Ejecuta audit_plan para verificar archivos en host y tareas del plan. Reporta estado final.`;
return `${prompt}\n\n${userText}`;
}
if (isFirst) {
return `${header}\n\n${userText}`;
}
return userMessage;
}
src / promptPreprocessor.ts
import { type PromptPreprocessorController, type ChatMessage } from "@lmstudio/sdk";
import { getWorkspaceDir } from "./utils.js";
const HEADER = `[nano-fs: workspace={{WORKSPACE_DIR}}]
Tools: write_file, read_file, edit_file, list_dir, make_dir, delete_path, run_bash, run_python, plan_manager, audit_plan, subagent_task.`;
export async function promptPreprocessor(
ctl: PromptPreprocessorController,
userMessage: ChatMessage
): Promise<string | ChatMessage> {
const userText = typeof userMessage.getText === "function" ? userMessage.getText() : String(userMessage);
const trimmed = userText.trim();
const workspaceDir = getWorkspaceDir();
const header = HEADER.replace("{{WORKSPACE_DIR}}", workspaceDir);
let isFirst = false;
try {
const history = await ctl.pullHistory();
if (Array.isArray(history)) {
isFirst = history.length === 0;
} else if (history && typeof history === "object" && "messages" in (history as any)) {
isFirst = (history as any).messages.length === 0;
} else {
isFirst = true;
}
} catch {
isFirst = true;
}
// 1. /plan
if (/^\/plan(\s+.*)?$/i.test(trimmed)) {
const topic = trimmed.replace(/^\/plan\s*/i, "").trim();
const prompt = `${header}
[MODO /plan]: Diseña plan conciso para: "${topic || "proyecto"}".
1. Guarda tareas en plan.md con \`plan_manager(action="create", tasks=[...])\`.
2. Muestra resumen con checkboxes [ ]. Informa que se puede ejecutar con \`/goal\`.`;
return `${prompt}\n\n${userText}`;
}
// 2. /goal
if (/^\/goal(\s+.*)?$/i.test(trimmed)) {
const objective = trimmed.replace(/^\/goal\s*/i, "").trim();
const prompt = `${header}
[MODO /goal]: Ejecución continua sin parar para: "${objective || "completar plan"}".
1. Si no hay plan, créalo con plan_manager.
2. Ejecuta tareas paso a paso con write_file/edit_file/run_bash.
3. Delega subtareas pesadas/revisiones con subagent_task (offload a GPU secundaria AMD eGPU o Intel Arc).
4. Actualiza progreso con plan_manager(action="update_task").
5. REVISIÓN: Ejecuta audit_plan(files_to_check=[...]) al terminar y confirma PASSED.`;
return `${prompt}\n\n${userText}`;
}
// 3. /review o /audit
if (/^\/(review|audit)(\s+.*)?$/i.test(trimmed)) {
const prompt = `${header}
[MODO /review]: Ejecuta audit_plan para verificar archivos en host y tareas del plan. Reporta estado final.`;
return `${prompt}\n\n${userText}`;
}
if (isFirst) {
return `${header}\n\n${userText}`;
}
return userMessage;
}