diff --git a/core/promptFiles/parsePromptFile.ts b/core/promptFiles/parsePromptFile.ts index 4b6cf6917b8..06eb0458c76 100644 --- a/core/promptFiles/parsePromptFile.ts +++ b/core/promptFiles/parsePromptFile.ts @@ -15,7 +15,9 @@ export function parsePromptFile(path: string, content: string) { const version = preamble.version ?? 2; let systemMessage: string | undefined = undefined; - if (prompt.includes("")) { + // Require both tags: a `` with no matching `` would make + // `split("")[1]` undefined and crash on `.trim()`. + if (prompt.includes("") && prompt.includes("")) { systemMessage = prompt.split("")[1].split("")[0].trim(); prompt = prompt.split("")[1].trim(); } diff --git a/core/promptFiles/parsePromptFile.vitest.ts b/core/promptFiles/parsePromptFile.vitest.ts new file mode 100644 index 00000000000..dd8f508d090 --- /dev/null +++ b/core/promptFiles/parsePromptFile.vitest.ts @@ -0,0 +1,32 @@ +import { describe, expect, it } from "vitest"; + +import { parsePromptFile } from "./parsePromptFile.js"; + +describe("parsePromptFile", () => { + it("extracts the system message when both tags are present", () => { + const result = parsePromptFile( + "greeting.prompt", + "You are helpful\nSummarize the file", + ); + + expect(result.systemMessage).toBe("You are helpful"); + expect(result.prompt).toBe("Summarize the file"); + }); + + it("does not throw when has no closing tag", () => { + const content = "You forgot to close the tag\nSummarize the file"; + + expect(() => parsePromptFile("broken.prompt", content)).not.toThrow(); + + const result = parsePromptFile("broken.prompt", content); + expect(result.systemMessage).toBeUndefined(); + expect(result.prompt).toBe(content); + }); + + it("leaves the prompt untouched when there is no system block", () => { + const result = parsePromptFile("plain.prompt", "Just a prompt body"); + + expect(result.systemMessage).toBeUndefined(); + expect(result.prompt).toBe("Just a prompt body"); + }); +});