From dc123094111030b72fd3f3afabc6357f01045ab6 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Tue, 15 Oct 2024 22:50:14 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20Update=20changelog=20formats,=20?= =?UTF-8?q?tests,=20and=20poetry=20lines?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../content/docs/reference/scripts/system.mdx | 15 +- packages/core/src/changelog.test.ts | 20 +++ packages/core/src/changelog.ts | 28 ++- .../src/genaisrc/system.changelog.genai.js | 16 +- .../core/src/genaisrc/system.files.genai.js | 8 +- packages/core/src/promptdom.ts | 7 +- packages/core/src/systems.ts | 2 +- .../src/edits/edits_files_changelog.genai.mts | 9 + packages/sample/src/edits/fileedittest.mts | 7 +- packages/sample/src/edits/su/fib.ts | 163 ++++++++++++++++++ 10 files changed, 255 insertions(+), 20 deletions(-) create mode 100644 packages/sample/src/edits/edits_files_changelog.genai.mts diff --git a/docs/src/content/docs/reference/scripts/system.mdx b/docs/src/content/docs/reference/scripts/system.mdx index bf5bfb125d..88ccdaac7b 100644 --- a/docs/src/content/docs/reference/scripts/system.mdx +++ b/docs/src/content/docs/reference/scripts/system.mdx @@ -505,11 +505,12 @@ Generate changelog formatter edits `````js wrap title="system.changelog" system({ title: "Generate changelog formatter edits", - lineNumbers: true + lineNumbers: true, }) +$`## CHANGELOG file format -$`For partial updates of files, return one or more ChangeLogs (CLs) formatted as follows. Each CL must contain +For partial updates of large files, return one or more ChangeLogs (CLs) formatted as follows. Each CL must contain one or more code snippet changes for a single file. There can be multiple CLs for a single file. Each CL must start with a description of its changes. The CL must then list one or more pairs of (OriginalCode, ChangedCode) code snippets. In each such pair, OriginalCode must list all consecutive @@ -519,7 +520,8 @@ lines of code (again including the same few lines before and after the changes). OriginalCode and ChangedCode must start at the same source code line number N. Each listed code line, in both the OriginalCode and ChangedCode snippets, must be prefixed with [N] that matches the line index N in the above snippets, and then be prefixed with exactly the same whitespace indentation as -the original snippets above. See also the following examples of the expected response format. +the original snippets above. Each OriginalCode must be paired with ChangedCode. Do NOT add multiple ChangedCode per OriginalCode. +See also the following examples of the expected response format. CHANGELOG: \`\`\`\`\`changelog @@ -553,7 +555,14 @@ OriginalCode@23-23: ChangedCode@23-23: [23] \`\`\`\`\` + +## Choosing what file format to use + +- If the file content is small (< 20 lines), use the full FULL format. +- If the file content is large (> 50 lines), use CHANGELOG format. +- If the file content IS VERY LARGE, ALWAYS USE CHANGELOG to save tokens. ` + ````` diff --git a/packages/core/src/changelog.test.ts b/packages/core/src/changelog.test.ts index dd7b5f92a4..7eb1634af2 100644 --- a/packages/core/src/changelog.test.ts +++ b/packages/core/src/changelog.test.ts @@ -259,4 +259,24 @@ ChangedCode@105-107: console.log(res) assert.equal(res[0].filename, "src/edits/su/fib.ts") }) + + test("unbalancred fences", () => { + const source = `\`\`\`\`\`changelog +ChangeLog:1@src/edits/bigfibs/fib.py +Description: Implemented new_function, removed comments and empty lines. +OriginalCode@48-51: +[48] def new_function(sum): +[49] # TODO +[50] return 0 +[51] # return (10 - (sum % 10)) % 10; +ChangedCode@48-50: +[48] def new_function(sum): +[49] return (10 - (sum % 10)) % 10 +[50] +\`\`\` +` + const res = parseChangeLogs(source) + console.log(res) + assert.equal(res[0].filename, "src/edits/bigfibs/fib.py") + }) }) diff --git a/packages/core/src/changelog.ts b/packages/core/src/changelog.ts index 15741ffe18..a2ca5c2e05 100644 --- a/packages/core/src/changelog.ts +++ b/packages/core/src/changelog.ts @@ -3,6 +3,8 @@ * A changelog describes changes between original and modified code segments. */ +import { unfence } from "./fence" + // Represents a chunk of code with a start and end line and its content. export interface ChangeLogChunk { start: number // Starting line number @@ -31,19 +33,26 @@ export interface ChangeLog { * @returns An array of parsed ChangeLog objects. */ export function parseChangeLogs(source: string): ChangeLog[] { - const lines = source.split("\n") + const lines = unfence(source, "changelog").split("\n") const changelogs: ChangeLog[] = [] // Process each line to extract changelog information. while (lines.length) { if (!lines[0].trim()) { lines.shift() - continue // Skip empty lines + continue + } + + // each back ticks + if (/^[\`\.]{3,}/.test(lines[0])) { + lines.shift() + continue } // Parse the ChangeLog header line. - let m = /^ChangeLog:\s*(?\d+)@(?.*)$/i.exec(lines[0]) - if (!m) throw new Error("missing ChangeLog header in " + lines[0]) + let m = /^ChangeLog:\s*(?\d+)@(?.*)\s*$/i.exec(lines[0]) + if (!m) + throw new Error("missing ChangeLog header in |" + lines[0] + "|") const changelog: ChangeLog = { index: parseInt(m.groups.index), filename: m.groups.file.trim(), @@ -66,6 +75,14 @@ export function parseChangeLogs(source: string): ChangeLog[] { lines.shift() continue } + + // each back ticks + if (/^[\`\.]{3,}/.test(lines[0])) { + // somehow we have finished this changed + lines.shift() + continue + } + // Attempt to parse a change. const change = parseChange() if (change) changelog.changes.push(change) @@ -89,7 +106,8 @@ export function parseChangeLogs(source: string): ChangeLog[] { lines.shift() const changed = parseChunk(m) - return { original, changed } + const res = { original, changed } + return res } // Parses a chunk of code from the changelog. diff --git a/packages/core/src/genaisrc/system.changelog.genai.js b/packages/core/src/genaisrc/system.changelog.genai.js index 684d22a5ea..30c6e9c2d7 100644 --- a/packages/core/src/genaisrc/system.changelog.genai.js +++ b/packages/core/src/genaisrc/system.changelog.genai.js @@ -1,10 +1,11 @@ system({ title: "Generate changelog formatter edits", - lineNumbers: true + lineNumbers: true, }) +$`## CHANGELOG file format -$`For partial updates of files, return one or more ChangeLogs (CLs) formatted as follows. Each CL must contain +For partial updates of large files, return one or more ChangeLogs (CLs) formatted as follows. Each CL must contain one or more code snippet changes for a single file. There can be multiple CLs for a single file. Each CL must start with a description of its changes. The CL must then list one or more pairs of (OriginalCode, ChangedCode) code snippets. In each such pair, OriginalCode must list all consecutive @@ -14,7 +15,8 @@ lines of code (again including the same few lines before and after the changes). OriginalCode and ChangedCode must start at the same source code line number N. Each listed code line, in both the OriginalCode and ChangedCode snippets, must be prefixed with [N] that matches the line index N in the above snippets, and then be prefixed with exactly the same whitespace indentation as -the original snippets above. See also the following examples of the expected response format. +the original snippets above. Each OriginalCode must be paired with ChangedCode. Do NOT add multiple ChangedCode per OriginalCode. +See also the following examples of the expected response format. CHANGELOG: \`\`\`\`\`changelog @@ -48,4 +50,10 @@ OriginalCode@23-23: ChangedCode@23-23: [23] \`\`\`\`\` -` \ No newline at end of file + +## Choosing what file format to use + +- If the file content is small (< 20 lines), use the full FULL format. +- If the file content is large (> 50 lines), use CHANGELOG format. +- If the file content IS VERY LARGE, ALWAYS USE CHANGELOG to save tokens. +` diff --git a/packages/core/src/genaisrc/system.files.genai.js b/packages/core/src/genaisrc/system.files.genai.js index 4e2ac4c000..9a23935157 100644 --- a/packages/core/src/genaisrc/system.files.genai.js +++ b/packages/core/src/genaisrc/system.files.genai.js @@ -4,9 +4,9 @@ system({ }) const folder = env.vars["outputFolder"] || "." -$`## Files +$`## FULL file format -When generating or updating files you will use the following syntax:` +When generating or updating files you may use the FULL file format:` def(`File ${folder}/file1.ts`, `What goes in\n${folder}/file1.ts.`, { language: "typescript", @@ -23,7 +23,9 @@ def(`File /path_to_file/file2.md`, `What goes in\n/path_to_file/file2.md.`, { $`- Make sure to use precisely \`\`\` to guard file code sections. - Always sure to use precisely \`\`\`\`\` to guard file markdown sections. -- Use full path of filename in code section header.` +- Use full path of filename in code section header. +- do NOT use ## headers with filename +` if (folder !== ".") $`When generating new files, place files in folder "${folder}".` $`- If a file does not have changes, do not regenerate. diff --git a/packages/core/src/promptdom.ts b/packages/core/src/promptdom.ts index 234f7393b2..92d26fed7a 100644 --- a/packages/core/src/promptdom.ts +++ b/packages/core/src/promptdom.ts @@ -243,7 +243,12 @@ function renderDefNode(def: PromptDefNode): string { while (dfence && body.includes(dfence)) { dfence += "`" } - const diffFormat = "" // body.length > 500 ? "preferred_diff_format=DIFF" : "" + const diffFormat = + body.length > 500 + ? " preferred_output_format=CHANGELOG " + : body.length < 200 + ? " preferred_output_format=FILE " + : "" const res = (name ? name + ":\n" : "") + dfence + diff --git a/packages/core/src/systems.ts b/packages/core/src/systems.ts index a42e628dbe..de4ce49da7 100644 --- a/packages/core/src/systems.ts +++ b/packages/core/src/systems.ts @@ -45,7 +45,7 @@ export function resolveSystems( if (/\Wchangelog\W/i.test(jsSource)) systems.push("system.changelog") else if (/\Wfile\W/i.test(jsSource)) { systems.push("system.files") - // systems.push("system.diff") + systems.push("system.changelog") // Add file schema system if schema is used if (useSchema) systems.push("system.files_schema") } diff --git a/packages/sample/src/edits/edits_files_changelog.genai.mts b/packages/sample/src/edits/edits_files_changelog.genai.mts new file mode 100644 index 0000000000..e0f8fb6879 --- /dev/null +++ b/packages/sample/src/edits/edits_files_changelog.genai.mts @@ -0,0 +1,9 @@ +import { editTest } from "./fileedittest.mts" +script({ + model: "large", + title: "system.diff test", + files: "src/edits/fibs/fib.*", + system: ["system", "system.files", "system.changelog"], +}) + +editTest() diff --git a/packages/sample/src/edits/fileedittest.mts b/packages/sample/src/edits/fileedittest.mts index 23eeced6f9..83d050e8b6 100644 --- a/packages/sample/src/edits/fileedittest.mts +++ b/packages/sample/src/edits/fileedittest.mts @@ -2,14 +2,15 @@ export function editTest() { def("FILE", env.files) $`- Implement the functions with TODO. -- Delete all comments +- Delete all comments in the entire file. This is important. - Delete all empty lines +- process all files, do NOT skip any ` defOutputProcessor((output) => { const { fileEdits } = output - if (Object.keys(fileEdits).length !== env.files.length) - throw new Error("no file edits") + const fns = Object.keys(fileEdits) + if (!fns.length) throw new Error("no file edits") for (const [fn, fe] of Object.entries(fileEdits)) { const res = fe.after if (/^\s*(#|\/\/).*$/m.test(res)) { diff --git a/packages/sample/src/edits/su/fib.ts b/packages/sample/src/edits/su/fib.ts index 50b0d5fc81..6b090769de 100644 --- a/packages/sample/src/edits/su/fib.ts +++ b/packages/sample/src/edits/su/fib.ts @@ -100,12 +100,175 @@ const poems = [ "A fleeting smile, a heart's grace.", "The sound of rain in the night.", "A gentle touch, a heart's warmth.", + "The whisper of the stars' song.", + "A single flame, a heart's light.", + "The promise of tomorrow in the night.", + "A fleeting thought, a heart's dream.", + "The sound of silence in the air.", + "A gentle rain, a heart's peace.", + "The whisper of love's embrace.", + "A single star, a heart's wish.", + "The promise of hope in the night.", + "A fleeting moment, a heart's truth.", + "The sound of waves in the night.", + "A gentle breeze, a heart's calm.", + "The whisper of the night wind.", + "A single tear, a heart's solace.", + "The promise of dawn in the dark.", + "A fleeting smile, a heart's grace.", + "The sound of rain in the night.", + "A gentle touch, a heart's warmth.", + "The whisper of the stars' song.", + "A single flame, a heart's light.", + "The promise of tomorrow in the night.", + "A fleeting thought, a heart's dream.", + "The sound of silence in the air.", + "A gentle rain, a heart's peace.", + "The whisper of love's embrace.", + "A single star, a heart's wish.", + "The promise of hope in the night.", + "A fleeting moment, a heart's truth.", + "The sound of waves in the night.", + "A gentle breeze, a heart's calm.", + "The whisper of the night wind.", + "A single tear, a heart's solace.", + "The promise of dawn in the dark.", + "A fleeting smile, a heart's grace.", + "The sound of rain in the night.", + "A gentle touch, a heart's warmth.", + "The whisper of the stars' song.", + "A single flame, a heart's light.", + "The promise of tomorrow in the night.", + "A fleeting thought, a heart's dream.", + "The sound of silence in the air.", + "A gentle rain, a heart's peace.", + "The whisper of love's embrace.", + "A single star, a heart's wish.", + "The promise of hope in the night.", + "A fleeting moment, a heart's truth.", + "The sound of waves in the night.", + "A gentle breeze, a heart's calm.", + "The whisper of the night wind.", + "A single tear, a heart's solace.", + "The promise of dawn in the dark.", + "A fleeting smile, a heart's grace.", + "The sound of rain in the night.", + "A gentle touch, a heart's warmth.", + "The whisper of the stars' song.", + "A single flame, a heart's light.", + "The promise of tomorrow in the night.", + "A fleeting thought, a heart's dream.", + "The sound of silence in the air.", + "A gentle rain, a heart's peace.", + "The whisper of love's embrace.", + "A single star, a heart's wish.", + "The promise of hope in the night.", + "A fleeting moment, a heart's truth.", + "The sound of waves in the night.", + "A gentle breeze, a heart's calm.", + "The whisper of the night wind.", + "A single tear, a heart's solace.", + "The promise of dawn in the dark.", + "A fleeting smile, a heart's grace.", + "The sound of rain in the night.", + "A gentle touch, a heart's warmth.", ] function fibonacci(n: number): number { // TODO: implement fibonacci algorithm return 0 // BODY } const morePoems = [ + "The whisper of the stars' song.", + "A single flame, a heart's light.", + "The promise of tomorrow in the night.", + "A fleeting thought, a heart's dream.", + "The sound of silence in the air.", + "A gentle rain, a heart's peace.", + "The whisper of love's embrace.", + "A single star, a heart's wish.", + "The promise of hope in the night.", + "A fleeting moment, a heart's truth.", + "The sound of waves in the night.", + "A gentle breeze, a heart's calm.", + "The whisper of the night wind.", + "A single tear, a heart's solace.", + "The promise of dawn in the dark.", + "A fleeting smile, a heart's grace.", + "The sound of rain in the night.", + "A gentle touch, a heart's warmth.", + "The whisper of the stars' song.", + "A single flame, a heart's light.", + "The promise of tomorrow in the night.", + "A fleeting thought, a heart's dream.", + "The sound of silence in the air.", + "A gentle rain, a heart's peace.", + "The whisper of love's embrace.", + "A single star, a heart's wish.", + "The promise of hope in the night.", + "A fleeting moment, a heart's truth.", + "The sound of waves in the night.", + "A gentle breeze, a heart's calm.", + "The whisper of the night wind.", + "A single tear, a heart's solace.", + "The promise of dawn in the dark.", + "A fleeting smile, a heart's grace.", + "The sound of rain in the night.", + "A gentle touch, a heart's warmth.", + "The whisper of the stars' song.", + "A single flame, a heart's light.", + "The promise of tomorrow in the night.", + "A fleeting thought, a heart's dream.", + "The sound of silence in the air.", + "A gentle rain, a heart's peace.", + "The whisper of love's embrace.", + "A single star, a heart's wish.", + "The promise of hope in the night.", + "A fleeting moment, a heart's truth.", + "The sound of waves in the night.", + "A gentle breeze, a heart's calm.", + "The whisper of the night wind.", + "A single tear, a heart's solace.", + "The promise of dawn in the dark.", + "A fleeting smile, a heart's grace.", + "The sound of rain in the night.", + "A gentle touch, a heart's warmth.", + "The whisper of the stars' song.", + "A single flame, a heart's light.", + "The promise of tomorrow in the night.", + "A fleeting thought, a heart's dream.", + "The sound of silence in the air.", + "A gentle rain, a heart's peace.", + "The whisper of love's embrace.", + "A single star, a heart's wish.", + "The promise of hope in the night.", + "A fleeting moment, a heart's truth.", + "The sound of waves in the night.", + "A gentle breeze, a heart's calm.", + "The whisper of the night wind.", + "A single tear, a heart's solace.", + "The promise of dawn in the dark.", + "A fleeting smile, a heart's grace.", + "The sound of rain in the night.", + "A gentle touch, a heart's warmth.", + "The whisper of the stars' song.", + "A single flame, a heart's light.", + "The promise of tomorrow in the night.", + "A fleeting thought, a heart's dream.", + "The sound of silence in the air.", + "A gentle rain, a heart's peace.", + "The whisper of love's embrace.", + "A single star, a heart's wish.", + "The promise of hope in the night.", + "A fleeting moment, a heart's truth.", + "The sound of waves in the night.", + "A gentle breeze, a heart's calm.", + "The whisper of the night wind.", + "A single tear, a heart's solace.", + "The promise of dawn in the dark.", + "A fleeting smile, a heart's grace.", + "The sound of rain in the night.", + "A gentle touch, a heart's warmth.", + "A whisper of dawn in the night's embrace.", "The scent of jasmine in the evening air.", "A fleeting shadow, a heart's echo.",