Skip to content

Commit 59a446e

Browse files
committed
Separate partial and full theme validation
1 parent d9eae57 commit 59a446e

File tree

1 file changed

+104
-101
lines changed

1 file changed

+104
-101
lines changed

src/tools/index.ts

Lines changed: 104 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ const polarisUnifiedEnabled =
1616
const liquidMcpEnabled =
1717
process.env.LIQUID_MCP === "true" || process.env.LIQUID_MCP === "1";
1818

19+
// LIQUID_VALIDATION_MODE can be "full" or "partial"
20+
const liquidMcpValidationMode =
21+
process.env.LIQUID_VALIDATION_MODE === "partial" ? "partial" : "full";
22+
1923
const GettingStartedAPISchema = z.object({
2024
name: z.string(),
2125
description: z.string(),
@@ -557,111 +561,110 @@ function liquidMcpTools(server: McpServer) {
557561
return;
558562
}
559563

560-
const themeRepositoryDescription = `A theme repository is a directory that MUST contain the following directories: snippets, sections, config, templates. It can optionally contain assets, locales, blocks, layouts.`;
561-
562-
server.tool(
563-
"validate_theme_codeblocks",
564-
`This tool validates Liquid codeblocks, Liquid files, and supporting Theme files (e.g. JSON locale files, JSON config files, JSON template files, JavaScript files, CSS files, and SVG files) generated or updated by LLMs to ensure they don't have hallucinated Liquid content, or incorrect references.
565-
566-
DO NOT use this tool if the user is asking to add, update, or delete files within a Theme repository - Use \`validate_theme\` instead. ${themeRepositoryDescription}
567-
568-
Provide every codeblock that was generated or updated by the LLM to this tool.`,
569-
570-
withConversationId({
571-
codeblocks: z
572-
.array(
573-
z.object({
574-
fileName: z
575-
.string()
576-
.describe(
577-
"The filename of the codeblock. If the filename is not provided, the filename should be descriptive of the codeblock's purpose, and should be in dashcase. Include file extension in the filename.",
578-
),
579-
fileType: z
580-
.enum([
581-
"assets",
582-
"blocks",
583-
"config",
584-
"layout",
585-
"locales",
586-
"sections",
587-
"snippets",
588-
"templates",
589-
])
590-
.default("blocks")
591-
.describe(
592-
"The type of codeblock generated. All JavaScript, CSS, and SVG files are in assets folder. Locale files are JSON files located in the locale folder. If the translation is only used in schemas, it should be in `locales/en(.default).schema.json`; if the translation is used anywhere in the liquid code, it should be in `en(.default).json`. The brackets show an optional default locale. The locale code should be the two-letter code for the locale.",
593-
),
594-
content: z.string().describe("The content of the file."),
595-
}),
596-
)
597-
.describe("An array of codeblocks to validate."),
598-
}),
599-
async (params) => {
600-
const validationResponses = await validateThemeCodeblocks(
601-
params.codeblocks,
602-
);
603-
604-
recordUsage(
605-
"validate_theme_codeblocks",
606-
params,
607-
validationResponses,
608-
).catch(() => {});
609-
610-
const responseText = formatValidationResult(
611-
validationResponses,
612-
"Theme Codeblocks",
613-
);
614-
615-
return {
616-
content: [
617-
{
618-
type: "text" as const,
619-
text: responseText,
620-
},
621-
],
622-
isError: hasFailedValidation(validationResponses),
623-
};
624-
},
625-
);
626-
627-
server.tool(
628-
"validate_theme",
629-
`This tool MUST run if the user asks the LLM to create or modify Liquid code inside their Theme repository. ${themeRepositoryDescription}
564+
const toolDescription = `This tool validates Liquid codeblocks, Liquid files, and supporting Theme files (e.g. JSON locale files, JSON config files, JSON template files, JavaScript files, CSS files, and SVG files) generated or updated by LLMs to ensure they don't have hallucinated Liquid content, invalid syntax, or incorrect references`;
565+
566+
if (liquidMcpValidationMode === "partial") {
567+
server.tool(
568+
"validate_theme_codeblocks",
569+
`${toolDescription}. Provide every codeblock that was generated or updated by the LLM to this tool.`,
570+
571+
withConversationId({
572+
codeblocks: z
573+
.array(
574+
z.object({
575+
fileName: z
576+
.string()
577+
.describe(
578+
"The filename of the codeblock. If the filename is not provided, the filename should be descriptive of the codeblock's purpose, and should be in dashcase. Include file extension in the filename.",
579+
),
580+
fileType: z
581+
.enum([
582+
"assets",
583+
"blocks",
584+
"config",
585+
"layout",
586+
"locales",
587+
"sections",
588+
"snippets",
589+
"templates",
590+
])
591+
.default("blocks")
592+
.describe(
593+
"The type of codeblock generated. All JavaScript, CSS, and SVG files are in assets folder. Locale files are JSON files located in the locale folder. If the translation is only used in schemas, it should be in `locales/en(.default).schema.json`; if the translation is used anywhere in the liquid code, it should be in `en(.default).json`. The brackets show an optional default locale. The locale code should be the two-letter code for the locale.",
594+
),
595+
content: z.string().describe("The content of the file."),
596+
}),
597+
)
598+
.describe("An array of codeblocks to validate."),
599+
}),
600+
async (params) => {
601+
const validationResponses = await validateThemeCodeblocks(
602+
params.codeblocks,
603+
);
630604

631-
Only fix the errors in the files that are directly related to the user's prompt. Offer to fix other errors if the user asks for it.`,
605+
recordUsage(
606+
"validate_theme_codeblocks",
607+
params,
608+
validationResponses,
609+
).catch(() => {});
632610

633-
withConversationId({
634-
absoluteThemePath: z
635-
.string()
636-
.describe("The absolute path to the theme directory"),
637-
filesCreatedOrUpdated: z
638-
.array(z.string())
639-
.describe(
640-
"An array of relative file paths that was generated or updated by the LLM. The file paths should be relative to the theme directory.",
641-
),
642-
}),
611+
const responseText = formatValidationResult(
612+
validationResponses,
613+
"Theme Codeblocks",
614+
);
643615

644-
async (params) => {
645-
const validationResponses = await validateTheme(
646-
params.absoluteThemePath,
647-
params.filesCreatedOrUpdated,
648-
);
616+
return {
617+
content: [
618+
{
619+
type: "text" as const,
620+
text: responseText,
621+
},
622+
],
623+
isError: hasFailedValidation(validationResponses),
624+
};
625+
},
626+
);
627+
} else {
628+
server.tool(
629+
"validate_theme",
630+
`${toolDescription}. Run this tool if the user is creating, updating, or deleting files inside of a Shopify Theme directory.`,
631+
632+
withConversationId({
633+
absoluteThemePath: z
634+
.string()
635+
.describe("The absolute path to the theme directory"),
636+
filesCreatedOrUpdated: z
637+
.array(z.string())
638+
.describe(
639+
"An array of relative file paths that was generated or updated by the LLM. The file paths should be relative to the theme directory.",
640+
),
641+
}),
642+
643+
async (params) => {
644+
const validationResponses = await validateTheme(
645+
params.absoluteThemePath,
646+
params.filesCreatedOrUpdated,
647+
);
649648

650-
recordUsage("validate_theme", params, validationResponses).catch(
651-
() => {},
652-
);
649+
recordUsage("validate_theme", params, validationResponses).catch(
650+
() => {},
651+
);
653652

654-
const responseText = formatValidationResult(validationResponses, "Theme");
653+
const responseText = formatValidationResult(
654+
validationResponses,
655+
"Theme",
656+
);
655657

656-
return {
657-
content: [
658-
{
659-
type: "text" as const,
660-
text: responseText,
661-
},
662-
],
663-
isError: hasFailedValidation(validationResponses),
664-
};
665-
},
666-
);
658+
return {
659+
content: [
660+
{
661+
type: "text" as const,
662+
text: responseText,
663+
},
664+
],
665+
isError: hasFailedValidation(validationResponses),
666+
};
667+
},
668+
);
669+
}
667670
}

0 commit comments

Comments
 (0)