184 lines
5.7 KiB
JavaScript
184 lines
5.7 KiB
JavaScript
import { pool } from "../../shared/db/pool.js";
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// Prompt Templates - CRUD con versionado
|
|
// ─────────────────────────────────────────────────────────────
|
|
|
|
// Prompt keys válidos
|
|
export const PROMPT_KEYS = ["router", "greeting", "orders", "shipping", "payment", "browse"];
|
|
|
|
// Modelos por defecto para cada prompt
|
|
export const DEFAULT_MODELS = {
|
|
router: "gpt-4o-mini",
|
|
greeting: "gpt-4-turbo",
|
|
orders: "gpt-4-turbo",
|
|
shipping: "gpt-4o-mini",
|
|
payment: "gpt-4o-mini",
|
|
browse: "gpt-4-turbo",
|
|
};
|
|
|
|
/**
|
|
* Obtiene el prompt activo para un tenant y key
|
|
* @returns {Object|null} { id, prompt_key, content, model, version, is_active, created_at, created_by }
|
|
*/
|
|
export async function getActivePrompt({ tenantId, promptKey }) {
|
|
const sql = `
|
|
SELECT id, prompt_key, content, model, version, is_active, created_at, created_by
|
|
FROM prompt_templates
|
|
WHERE tenant_id = $1 AND prompt_key = $2 AND is_active = true
|
|
LIMIT 1
|
|
`;
|
|
const { rows } = await pool.query(sql, [tenantId, promptKey]);
|
|
return rows[0] || null;
|
|
}
|
|
|
|
/**
|
|
* Lista todos los prompts activos de un tenant
|
|
*/
|
|
export async function listActivePrompts({ tenantId }) {
|
|
const sql = `
|
|
SELECT id, prompt_key, content, model, version, is_active, created_at, created_by
|
|
FROM prompt_templates
|
|
WHERE tenant_id = $1 AND is_active = true
|
|
ORDER BY prompt_key
|
|
`;
|
|
const { rows } = await pool.query(sql, [tenantId]);
|
|
return rows;
|
|
}
|
|
|
|
/**
|
|
* Obtiene todas las versiones de un prompt
|
|
*/
|
|
export async function getPromptVersions({ tenantId, promptKey, limit = 20 }) {
|
|
const sql = `
|
|
SELECT id, prompt_key, content, model, version, is_active, created_at, created_by
|
|
FROM prompt_templates
|
|
WHERE tenant_id = $1 AND prompt_key = $2
|
|
ORDER BY version DESC
|
|
LIMIT $3
|
|
`;
|
|
const { rows } = await pool.query(sql, [tenantId, promptKey, limit]);
|
|
return rows;
|
|
}
|
|
|
|
/**
|
|
* Obtiene una versión específica de un prompt
|
|
*/
|
|
export async function getPromptVersion({ tenantId, promptKey, version }) {
|
|
const sql = `
|
|
SELECT id, prompt_key, content, model, version, is_active, created_at, created_by
|
|
FROM prompt_templates
|
|
WHERE tenant_id = $1 AND prompt_key = $2 AND version = $3
|
|
LIMIT 1
|
|
`;
|
|
const { rows } = await pool.query(sql, [tenantId, promptKey, version]);
|
|
return rows[0] || null;
|
|
}
|
|
|
|
/**
|
|
* Desactiva el prompt activo actual (para crear nueva versión)
|
|
*/
|
|
export async function deactivatePrompt({ tenantId, promptKey }) {
|
|
const sql = `
|
|
UPDATE prompt_templates
|
|
SET is_active = false
|
|
WHERE tenant_id = $1 AND prompt_key = $2 AND is_active = true
|
|
`;
|
|
await pool.query(sql, [tenantId, promptKey]);
|
|
}
|
|
|
|
/**
|
|
* Crea una nueva versión del prompt (automáticamente desactiva la anterior)
|
|
* @returns {Object} El prompt creado con su versión
|
|
*/
|
|
export async function createPrompt({ tenantId, promptKey, content, model, createdBy = null }) {
|
|
// Validar prompt_key
|
|
if (!PROMPT_KEYS.includes(promptKey)) {
|
|
throw new Error(`Invalid prompt_key: ${promptKey}. Valid keys: ${PROMPT_KEYS.join(", ")}`);
|
|
}
|
|
|
|
// Desactivar versión anterior
|
|
await deactivatePrompt({ tenantId, promptKey });
|
|
|
|
// Insertar nueva versión (el trigger calcula la versión automáticamente)
|
|
const sql = `
|
|
INSERT INTO prompt_templates (tenant_id, prompt_key, content, model, is_active, created_by)
|
|
VALUES ($1, $2, $3, $4, true, $5)
|
|
RETURNING id, prompt_key, content, model, version, is_active, created_at, created_by
|
|
`;
|
|
const { rows } = await pool.query(sql, [
|
|
tenantId,
|
|
promptKey,
|
|
content,
|
|
model || DEFAULT_MODELS[promptKey] || "gpt-4-turbo",
|
|
createdBy,
|
|
]);
|
|
return rows[0];
|
|
}
|
|
|
|
/**
|
|
* Restaura una versión anterior del prompt (crea nueva versión con el contenido antiguo)
|
|
*/
|
|
export async function rollbackPrompt({ tenantId, promptKey, toVersion, createdBy = null }) {
|
|
// Obtener la versión a restaurar
|
|
const oldVersion = await getPromptVersion({ tenantId, promptKey, version: toVersion });
|
|
if (!oldVersion) {
|
|
throw new Error(`Version ${toVersion} not found for prompt ${promptKey}`);
|
|
}
|
|
|
|
// Crear nueva versión con el contenido antiguo
|
|
return createPrompt({
|
|
tenantId,
|
|
promptKey,
|
|
content: oldVersion.content,
|
|
model: oldVersion.model,
|
|
createdBy,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Resetea un prompt a su default (desactiva todas las versiones custom)
|
|
*/
|
|
export async function resetPromptToDefault({ tenantId, promptKey }) {
|
|
const sql = `
|
|
UPDATE prompt_templates
|
|
SET is_active = false
|
|
WHERE tenant_id = $1 AND prompt_key = $2
|
|
`;
|
|
await pool.query(sql, [tenantId, promptKey]);
|
|
return { success: true, message: `Prompt ${promptKey} reset to default` };
|
|
}
|
|
|
|
/**
|
|
* Elimina todas las versiones de un prompt (usar con cuidado)
|
|
*/
|
|
export async function deleteAllPromptVersions({ tenantId, promptKey }) {
|
|
const sql = `
|
|
DELETE FROM prompt_templates
|
|
WHERE tenant_id = $1 AND prompt_key = $2
|
|
RETURNING id
|
|
`;
|
|
const { rows } = await pool.query(sql, [tenantId, promptKey]);
|
|
return { deleted: rows.length };
|
|
}
|
|
|
|
/**
|
|
* Obtiene estadísticas de prompts de un tenant
|
|
*/
|
|
export async function getPromptStats({ tenantId }) {
|
|
const sql = `
|
|
SELECT
|
|
prompt_key,
|
|
COUNT(*) as total_versions,
|
|
MAX(version) as latest_version,
|
|
MAX(CASE WHEN is_active THEN version END) as active_version,
|
|
MAX(created_at) as last_updated
|
|
FROM prompt_templates
|
|
WHERE tenant_id = $1
|
|
GROUP BY prompt_key
|
|
ORDER BY prompt_key
|
|
`;
|
|
const { rows } = await pool.query(sql, [tenantId]);
|
|
return rows;
|
|
}
|