x
This commit is contained in:
1 parent
8f64d89f6f
commit
b17e589577
18 files changed
+918
-517
No files matched your search
@@ -38,6 +38,23 @@ const SECTION_TOOL_CONFIGS = [
|
||||
},
|
||||
required: ["sectionId"]
|
||||
},
|
||||
{
|
||||
name: "update_editorial_tile",
|
||||
sectionType: "EDITORIAL_TILE",
|
||||
description: `Update an EDITORIAL_TILE section. Title, description, and buttonText are localized. imageUrl, imagePosition, buttonLink, backgroundColor, and textColor are plain strings. Example payload: { "sectionId": 12, "title": ${localizedStringExample}, "description": ${localizedStringExample}, "imageUrl": "https://..." }`,
|
||||
properties: {
|
||||
sectionId: { type: "number", description: "The numeric ID of the section to update" },
|
||||
imageUrl: { type: "string", description: "Plain string main image URL" },
|
||||
imagePosition: { type: "string", description: "Plain string image position ('left' or 'right')" },
|
||||
title: { ...localizedStringSchema, description: `Localized title, for example ${localizedStringExample}` },
|
||||
description: { ...localizedStringSchema, description: `Localized description, for example ${localizedStringExample}` },
|
||||
buttonText: { ...localizedStringSchema, description: `Localized button text, for example ${localizedStringExample}` },
|
||||
buttonLink: { type: "string", description: "Plain string button link URL" },
|
||||
backgroundColor: { type: "string", description: "Plain string background color in hex or rgba" },
|
||||
textColor: { type: "string", description: "Plain string text color in hex or rgba" }
|
||||
},
|
||||
required: ["sectionId"]
|
||||
},
|
||||
{
|
||||
name: "update_rich_text",
|
||||
sectionType: "RICH_TEXT",
|
||||
@@ -150,6 +167,35 @@ const SECTION_TOOL_CONFIGS = [
|
||||
subtitle: { ...localizedStringSchema, description: `Localized form subtitle, for example ${localizedStringExample}` }
|
||||
},
|
||||
required: ["sectionId"]
|
||||
},
|
||||
{
|
||||
name: "update_editorial_carousel",
|
||||
sectionType: "EDITORIAL_CAROUSEL",
|
||||
description: `Update an EDITORIAL_CAROUSEL section. title, description, and slides are supported. Example payload: { "sectionId": 12, "title": ${localizedStringExample}, "description": ${localizedStringExample} }`,
|
||||
properties: {
|
||||
sectionId: { type: "number", description: "The numeric ID of the section to update" },
|
||||
title: { ...localizedStringSchema, description: `Localized section title, for example ${localizedStringExample}` },
|
||||
description: { ...localizedStringSchema, description: `Localized section description, for example ${localizedStringExample}` },
|
||||
backgroundColor: { type: "string", description: "Plain string background color in hex or rgba" },
|
||||
textColor: { type: "string", description: "Plain string text color in hex or rgba" },
|
||||
slides: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
title: localizedStringSchema,
|
||||
description: localizedStringSchema,
|
||||
category: localizedStringSchema,
|
||||
imageUrl: { type: "string" },
|
||||
buttonText: localizedStringSchema,
|
||||
buttonLink: { type: "string" }
|
||||
},
|
||||
required: ["imageUrl"]
|
||||
},
|
||||
description: "Array of slides. IMPORTANT: Providing this will completely overwrite the existing slides array. Ensure you provide all slides."
|
||||
}
|
||||
},
|
||||
required: ["sectionId"]
|
||||
}
|
||||
] as const;
|
||||
|
||||
@@ -201,6 +247,18 @@ function buildSectionUpdateResult(toolName: string, sectionType: string, updated
|
||||
}
|
||||
|
||||
export const SECTION_TOOL_DEFINITIONS = [
|
||||
{
|
||||
name: "get_page_section",
|
||||
description: "Get a specific page section by ID, returning its hydrated payload resolving linked content like categories or products. Optionally pass lang to control translation.",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
sectionId: { type: "number", description: "The numeric ID of the section to fetch" },
|
||||
lang: { type: "string", description: "Optional language code (th, en, all)" }
|
||||
},
|
||||
required: ["sectionId"]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "add_page_section",
|
||||
description: "Add a block section to a dynamic page layout. For the payload field, ensure it matches the section type. Examples: For TEXT, use { \"text\": \"...\" }. For RICH_TEXT, use { \"title\": \"...\", \"content\": \"...\" }.",
|
||||
@@ -258,8 +316,21 @@ export const SECTION_TOOL_NAMES = new Set<string>(SECTION_TOOL_DEFINITIONS.map((
|
||||
export async function handleSectionTool(api: AxiosInstance, name: string, params: any) {
|
||||
if (!SECTION_TOOL_NAMES.has(name)) return null;
|
||||
|
||||
// Global validation: almost all section tools require sectionId, except add_page_section
|
||||
if (name !== "add_page_section" && params.sectionId === undefined) {
|
||||
throw new Error(`Validation Error: 'sectionId' is required for tool '${name}'`);
|
||||
}
|
||||
|
||||
switch (name) {
|
||||
case "get_page_section": {
|
||||
const langParam = params.lang ? `?lang=${params.lang}` : "";
|
||||
const res = await api.get(`/pages/sections/${params.sectionId}${langParam}`);
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
}
|
||||
case "add_page_section": {
|
||||
if (params.pageId === undefined) {
|
||||
throw new Error(`Validation Error: 'pageId' is required for tool '${name}'`);
|
||||
}
|
||||
const payload: any = {
|
||||
type: params.type,
|
||||
payload: params.payload,
|
||||
@@ -278,6 +349,7 @@ export async function handleSectionTool(api: AxiosInstance, name: string, params
|
||||
const res = await api.put(`/pages/sections/${params.sectionId}`, payload);
|
||||
return buildSectionUpdateResult("update_page_section", res.data?.type ?? params.type ?? "UNKNOWN", res.data, payload);
|
||||
}
|
||||
case "update_editorial_tile":
|
||||
case "update_hero_article":
|
||||
case "update_rich_text":
|
||||
case "update_scent_notes_breakdown":
|
||||
@@ -285,7 +357,8 @@ export async function handleSectionTool(api: AxiosInstance, name: string, params
|
||||
case "update_product_carousel":
|
||||
case "update_accordion":
|
||||
case "update_contact_info":
|
||||
case "update_contact_form": {
|
||||
case "update_contact_form":
|
||||
case "update_editorial_carousel": {
|
||||
const config = SECTION_TOOL_CONFIG_BY_NAME.get(name);
|
||||
if (!config) {
|
||||
throw new Error(`Unknown tool config for: ${name}`);
|
||||
@@ -299,9 +372,21 @@ export async function handleSectionTool(api: AxiosInstance, name: string, params
|
||||
payload.heartNotes = payload.middleNotes;
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch existing section to merge payload so AI doesn't have to provide all required fields every time
|
||||
let mergedPayload = payload;
|
||||
try {
|
||||
const existingRes = await api.get(`/pages/sections/${params.sectionId}?lang=all`);
|
||||
if (existingRes.data && existingRes.data.payload) {
|
||||
mergedPayload = { ...existingRes.data.payload, ...payload };
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(`Could not fetch existing section ${params.sectionId} for merging, proceeding with partial payload.`);
|
||||
}
|
||||
|
||||
const res = await api.put(`/pages/sections/${params.sectionId}`, {
|
||||
type: config.sectionType,
|
||||
...payload
|
||||
payload: mergedPayload
|
||||
});
|
||||
|
||||
return buildSectionUpdateResult(name, config.sectionType, res.data, payload);
|
||||
|
||||
Reference in new issue
Block a user