toque en imagenes y filtrado en los esquemas

This commit is contained in:
Jordan Diaz
2026-04-12 14:45:50 +00:00
parent f5b9e275c9
commit 15abc1eb4f
2 changed files with 36 additions and 12 deletions

View File

@@ -100,11 +100,11 @@ async function resolveLocalImageAsBase64(imageUrl) {
export function registerUploadRecordImageTool(server) { export function registerUploadRecordImageTool(server) {
server.tool( server.tool(
"upload_record_image", "upload_record_image",
"Upload an image to a specific record field in Acai CMS. Downloads the image from a URL and uploads it. Table names are WITHOUT the 'cms_' prefix. The recordId is the 'num' primary key, never 'id'. If the URL came from generate_image, prefer uploadUrl (or fullUrl) over dockerUrl in Forge environments.", "Upload an image to a specific record field in Acai CMS. MANDATORY: before calling this tool, you MUST call get_table_schema with minimal=true to find the EXACT upload field name. Look for fields with type='upload'. NEVER guess field names. Table names WITHOUT 'cms_' prefix. recordId is 'num', never 'id'. If the URL came from generate_image, prefer uploadUrl (or fullUrl) over dockerUrl.",
withAuthParams({ withAuthParams({
tableName: z.string().describe("Table name without 'cms_' prefix (e.g., 'productos')"), tableName: z.string().describe("Table name without 'cms_' prefix (e.g., 'productos')"),
recordId: z.string().describe("Record 'num' (primary key)"), recordId: z.string().describe("Record 'num' (primary key)"),
fieldName: z.string().describe("Field name (e.g., 'galeria_imagenes')"), fieldName: z.string().describe("EXACT field name from the schema. MUST match a field with type 'upload' from get_table_schema or get_module_config_vars. Do NOT guess."),
imageUrl: z.string().describe("URL of the image to upload"), imageUrl: z.string().describe("URL of the image to upload"),
alt: z.string().optional().describe("Alt text for the image (optional)"), alt: z.string().optional().describe("Alt text for the image (optional)"),
}), }),

View File

@@ -12,9 +12,10 @@ export function registerGetTableSchemaTool(server) {
withAuthParams({ withAuthParams({
tableName: z.string().describe("Table name without cms_ prefix"), tableName: z.string().describe("Table name without cms_ prefix"),
minimal: z.boolean().optional().describe("If true, returns only field names + types + labels"), minimal: z.boolean().optional().describe("If true, returns only field names + types + labels"),
filterFields: z.string().optional().describe("Filter field names containing these terms (pipe-separated, e.g. 'galeria|foto|image'). Only matching fields are returned. Useful to find the exact field name without loading the full schema."),
}), }),
{ readOnlyHint: true, destructiveHint: false }, { readOnlyHint: true, destructiveHint: false },
withAuth(async ({ tableName, minimal }, extra) => { withAuth(async ({ tableName, minimal, filterFields }, extra) => {
try { try {
const validationError = validateRequired({ tableName }, ['tableName'], 'get_table_schema'); const validationError = validateRequired({ tableName }, ['tableName'], 'get_table_schema');
if (validationError) return validationError; if (validationError) return validationError;
@@ -45,18 +46,41 @@ export function registerGetTableSchemaTool(server) {
const parsed = parseIniSchema(iniContent); const parsed = parseIniSchema(iniContent);
if (minimal) { // Filtrar campos si se pasa filterFields (pipe-separated terms)
const minimalSchema = { menuName: parsed.menuName, menuType: parsed.menuType, enlace: parsed.enlace }; let fields = parsed.fields || {};
const minFields = {}; if (filterFields) {
for (const [key, value] of Object.entries(parsed.fields || {})) { const terms = filterFields.toLowerCase().split("|").map(t => t.trim()).filter(Boolean);
minFields[key] = { type: value.type }; const filtered = {};
if (value.label) minFields[key].label = value.label; for (const [key, value] of Object.entries(fields)) {
const keyLower = key.toLowerCase();
const labelLower = (value.label || "").toLowerCase();
if (terms.some(t => keyLower.includes(t) || labelLower.includes(t))) {
filtered[key] = value;
}
}
fields = filtered;
if (Object.keys(fields).length === 0) {
return { content: [{ type: "text", text: JSON.stringify({
tableName, filterFields, matches: 0,
message: "No fields matching filter. Try broader terms or omit filterFields to see all.",
}, null, 2) }] };
} }
minimalSchema.fields = minFields;
return { content: [{ type: "text", text: JSON.stringify(minimalSchema, null, 2) }] };
} }
return { content: [{ type: "text", text: JSON.stringify(parsed, null, 2) }] }; if (minimal || filterFields) {
const result = { menuName: parsed.menuName, tableName };
const minFields = {};
for (const [key, value] of Object.entries(fields)) {
minFields[key] = { type: value.type };
if (value.label) minFields[key].label = value.label;
if (value.maxUploads) minFields[key].maxUploads = value.maxUploads;
}
result.fields = minFields;
if (filterFields) result.filterFields = filterFields;
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
}
return { content: [{ type: "text", text: JSON.stringify({ ...parsed, fields }, null, 2) }] };
} catch (error) { } catch (error) {
return handleToolError(error, 'get_table_schema', { tableName }); return handleToolError(error, 'get_table_schema', { tableName });
} }