Las cmsTables (tablas del CMS cuyo contenido MUESTRA un modulo) ya se definen desde Forge y desde el CMS legacy; faltaba que el agente las entendiera. - update_module_metadata acepta cmsTables. El endpoint del server ya la validaba, asi que solo habia que declararla en el schema Zod. - get_module_config_vars la devuelve: sale gratis porque el handler ya resolvia el schema del modulo para uploadFields/varsMeta. - Docs (01, 03, 09) con el matiz que mas se puede confundir: `tables` es donde viven los VALORES de las vars (siempre builder_custom, lo pone el compilador) y `cmsTables` es que contenido MUESTRA el modulo. Para el agente lo util no es solo escribirlas: al recibirlas sabe donde esta de verdad el contenido visible. Si le piden cambiar lo que muestra un listado de noticias, los registros estan en esa tabla, no en las vars del modulo. Se documenta ademas que la metadata del builder.json es la UNICA parte editable del fichero (y solo con esta tool): el resto lo regenera el compilador en cada compilacion.
98 lines
5.1 KiB
JavaScript
98 lines
5.1 KiB
JavaScript
import { z } from "zod";
|
|
import { withAuth } from "../../auth/index.js";
|
|
import { withAuthParams } from "../helpers/authSchema.js";
|
|
import { handleToolError, validateRequired } from "../helpers/errorHandler.js";
|
|
import { pythonGet } from "../helpers/pythonServerClient.js";
|
|
import { getCurrentProjectInfo } from "../files/helpers.js";
|
|
|
|
// get_module_config_vars
|
|
//
|
|
// Pasa por el server Python (/api/creator/get-module-vars) en lugar de ir
|
|
// directamente al PHP. Asi obtenemos `varsMeta`: para cada variable del
|
|
// modulo, su ubicacion fisica en `builder_custom` (recordNum + columna real).
|
|
// Sin esto el agente solo conoce el nombre humano de la variable (ej.
|
|
// `titulo`) y al hacer create_or_update_record adivina el campo y suele
|
|
// fallar silenciosamente porque la columna real es algo como `title2`.
|
|
|
|
export function registerGetModuleConfigVarsTool(server) {
|
|
server.tool(
|
|
"get_module_config_vars",
|
|
`Get the current configuration variable values for a module instance on a page record. Returns:
|
|
|
|
- vars: resolved values (text, HTML, etc.) for simple vars and arrays for multi/repeater vars
|
|
- varsMeta: per-var physical location { tableName: 'builder_custom', recordNum, fieldName, type }. USE THIS to know exactly which row + column to update with create_or_update_record. The variable's display name (e.g. 'titulo') is NOT the same as the physical column name (e.g. 'title2'). Uploads inside a 'multi' var carry their labels in subFields.<subVar>.infoLabels.
|
|
- uploadFields: per-var upload location for upload_record_image / replace_record_image / set_upload_info. Each entry includes infoLabels when the module defines them (array; position 0 = info1).
|
|
- cmsTables: CMS tables whose records this module DISPLAYS (e.g. ["noticias"]), or [] if it only shows its own variables. This is where the module's visible content really lives: if the user asks to change what a news-list module shows, the records are in those tables, NOT in the module's vars. Use list_table_records / create_or_update_record against them. Empty list means nothing to look up elsewhere.
|
|
- moduleId, sectionId
|
|
|
|
Required params:
|
|
- tableName (string) without 'cms_' prefix (parent page table, e.g. 'apartados')
|
|
- recordNum (number) parent record primary key ('num', never 'id')
|
|
- sectionId (string) section ID of the module instance`,
|
|
withAuthParams({
|
|
tableName: z.string().describe("Parent table name (e.g. 'apartados')"),
|
|
recordNum: z.number().describe("Parent record number"),
|
|
sectionId: z.string().describe("Section ID of the module instance"),
|
|
}),
|
|
{ readOnlyHint: true, destructiveHint: false },
|
|
withAuth(async ({ tableName, recordNum, sectionId }, _extra) => {
|
|
try {
|
|
const validationError = validateRequired(
|
|
{ tableName, recordNum, sectionId },
|
|
["tableName", "recordNum", "sectionId"],
|
|
"get_module_config_vars"
|
|
);
|
|
if (validationError) return validationError;
|
|
|
|
const { projectSlug } = getCurrentProjectInfo();
|
|
const result = await pythonGet("/api/creator/get-module-vars", {
|
|
project: projectSlug,
|
|
table: tableName,
|
|
num: recordNum,
|
|
sectionId,
|
|
});
|
|
|
|
// El endpoint Python devuelve la respuesta del PHP envuelta:
|
|
// { success, data: { moduleId, vars, configVars, uploadFields, varsMeta, ... } }
|
|
// o directamente las claves en raiz. Normalizamos.
|
|
const inner = result?.data && typeof result.data === "object" ? result.data : result;
|
|
if (!inner || inner.success === false) {
|
|
return {
|
|
content: [{
|
|
type: "text",
|
|
text: JSON.stringify({
|
|
success: false,
|
|
error: inner?.error || "Could not read module config vars",
|
|
}),
|
|
}],
|
|
isError: true,
|
|
};
|
|
}
|
|
|
|
return {
|
|
content: [{
|
|
type: "text",
|
|
text: JSON.stringify({
|
|
success: true,
|
|
action: "get_module_config_vars",
|
|
tableName,
|
|
recordNum,
|
|
sectionId,
|
|
data: {
|
|
moduleId: inner.moduleId,
|
|
sectionId: inner.sectionId,
|
|
vars: inner.vars || {},
|
|
varsMeta: inner.varsMeta || {},
|
|
uploadFields: inner.uploadFields || {},
|
|
configVars: inner.configVars || {},
|
|
},
|
|
}, null, 2),
|
|
}],
|
|
};
|
|
} catch (error) {
|
|
return handleToolError(error, "get_module_config_vars", { tableName, recordNum, sectionId });
|
|
}
|
|
})
|
|
);
|
|
}
|