diff --git a/docs/src/content/docs/reference/scripts/system.mdx b/docs/src/content/docs/reference/scripts/system.mdx index 19e9c897fb..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. ` + ````` @@ -590,7 +599,7 @@ system({ $`## DIFF file format -The DIFF format should be used to generate diff changes on large files: +The DIFF format should be used to generate diff changes on large files with small number of changes: - existing lines must start with their original line number: [] - deleted lines MUST start with - followed by the line number: - [] @@ -608,7 +617,7 @@ The DIFF format should be used to generate diff changes on large files: - only emit a couple unmodified lines before and after the changes - keep the diffs AS SMALL AS POSSIBLE - when reading files, ask for line numbers -- minimize the number of unmodified lines +- minimize the number of unmodified lines. DO NOT EMIT MORE THEN 2 UNMODIFIED LINES BEFORE AND AFTER THE CHANGES. Otherwise use the FILE file format. - do NOT generate diff for files that have no changes - do NOT emit diff if lines are the same @@ -623,36 +632,40 @@ The DIFF format should be used to generate diff changes on large files: FOLLOW THE SYNTAX PRECISLY. THIS IS IMPORTANT. DIFF ./file.ts: \`\`\`diff -[original line number] <2 lines before changes (not the whole file)> +[original line number] line before changes - [original line number] + -[original line number] <2 lines after changes (not the whole file)> +[original line number] line after changes \`\`\` DIFF ./file2.ts: \`\`\`diff -[original line number] <2 lines before changes (not the whole file)> +[original line number] line before changes - [original line number] - [original line number] + + -[original line number] <2 lines after changes (not the whole file)> +[original line number] line after changes \`\`\` DIFF ./file3.ts: \`\`\`diff -[original line number] <2 lines before changes (not the whole file)> +[original line number] line before changes + -[original line number] <2 lines after changes (not the whole file)> +[original line number] line after changes \`\`\` DIFF ./file4.ts: \`\`\`diff -[original line number] <2 lines before changes (not the whole file)> +[original line number] line before changes - [original line number] -[original line number] <2 lines after changes (not the whole file)> +[original line number] line after changes \`\`\` +## Choosing what file format to use + +- If the file content is large (> 50 lines) and the changes are small, use the DIFF format. +- In all other cases, use the FILE file format. ` ````` @@ -688,9 +701,9 @@ system({ }) const folder = env.vars["outputFolder"] || "." -$`## Files +$`## FILE file format -When generating or updating files you will use the following syntax:` +When generating or updating files you should use the FILE file syntax preferrably:` def(`File ${folder}/file1.ts`, `What goes in\n${folder}/file1.ts.`, { language: "typescript", @@ -705,9 +718,24 @@ def(`File /path_to_file/file2.md`, `What goes in\n/path_to_file/file2.md.`, { language: "markdown", }) +$`You MUST specify a start_line and end_line to only update a specific part of a file: + +FILE ${folder}/file1.py: +\`\`\`python start_line=15 end_line=20 +Replace line range 15-20 in \n${folder}/file1.py +\`\`\` + +FILE ${folder}/file1.py: +\`\`\`python start_line=30 end_line=35 +Replace line range 30-35 in \n${folder}/file1.py +\`\`\` + +` + $`- 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. +- Use start_line, end_line for large files with small updates` 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/changelog.test.ts b/packages/core/src/changelog.test.ts index 1d7d59a2a6..7eb1634af2 100644 --- a/packages/core/src/changelog.test.ts +++ b/packages/core/src/changelog.test.ts @@ -241,4 +241,42 @@ ChangedCode@46-48: console.log(res) assert.equal(res[0].filename, "packages/core/src/cancellation.ts") }) + + test("missing header", () => { + const source = ` +ChangeLog:1@src/edits/su/fib.ts +Description: Implement the Fibonacci function and remove comments and empty lines. +OriginalCode@105-107: +[105] // TODO: implement fibonacci algorithm +[106] return 0 // BODY +[107] } +ChangedCode@105-107: +[105] if (n <= 1) return n; +[106] return fibonacci(n - 1) + fibonacci(n - 2); +[107] } +` + const res = parseChangeLogs(source) + 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.diff.genai.js b/packages/core/src/genaisrc/system.diff.genai.js index 1fd11966ca..f8ab46175f 100644 --- a/packages/core/src/genaisrc/system.diff.genai.js +++ b/packages/core/src/genaisrc/system.diff.genai.js @@ -5,7 +5,7 @@ system({ $`## DIFF file format -The DIFF format should be used to generate diff changes on large files: +The DIFF format should be used to generate diff changes on large files with small number of changes: - existing lines must start with their original line number: [] - deleted lines MUST start with - followed by the line number: - [] @@ -23,7 +23,7 @@ The DIFF format should be used to generate diff changes on large files: - only emit a couple unmodified lines before and after the changes - keep the diffs AS SMALL AS POSSIBLE - when reading files, ask for line numbers -- minimize the number of unmodified lines +- minimize the number of unmodified lines. DO NOT EMIT MORE THEN 2 UNMODIFIED LINES BEFORE AND AFTER THE CHANGES. Otherwise use the FILE file format. - do NOT generate diff for files that have no changes - do NOT emit diff if lines are the same @@ -38,34 +38,38 @@ The DIFF format should be used to generate diff changes on large files: FOLLOW THE SYNTAX PRECISLY. THIS IS IMPORTANT. DIFF ./file.ts: \`\`\`diff -[original line number] <2 lines before changes (not the whole file)> +[original line number] line before changes - [original line number] + -[original line number] <2 lines after changes (not the whole file)> +[original line number] line after changes \`\`\` DIFF ./file2.ts: \`\`\`diff -[original line number] <2 lines before changes (not the whole file)> +[original line number] line before changes - [original line number] - [original line number] + + -[original line number] <2 lines after changes (not the whole file)> +[original line number] line after changes \`\`\` DIFF ./file3.ts: \`\`\`diff -[original line number] <2 lines before changes (not the whole file)> +[original line number] line before changes + -[original line number] <2 lines after changes (not the whole file)> +[original line number] line after changes \`\`\` DIFF ./file4.ts: \`\`\`diff -[original line number] <2 lines before changes (not the whole file)> +[original line number] line before changes - [original line number] -[original line number] <2 lines after changes (not the whole file)> +[original line number] line after changes \`\`\` +## Choosing what file format to use + +- If the file content is large (> 50 lines) and the changes are small, use the DIFF format. +- In all other cases, use the FILE file format. ` 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/genaisrc/system.files.genai.mjs b/packages/core/src/genaisrc/system.files.genai.mjs new file mode 100644 index 0000000000..92162a97ff --- /dev/null +++ b/packages/core/src/genaisrc/system.files.genai.mjs @@ -0,0 +1,46 @@ +system({ + title: "File generation", + description: "Teaches the file format supported by GenAIScripts", +}) + +const folder = env.vars["outputFolder"] || "." +$`## FILE file format + +When generating or updating files you should use the FILE file syntax preferrably:` + +def(`File ${folder}/file1.ts`, `What goes in\n${folder}/file1.ts.`, { + language: "typescript", +}) +def(`File ${folder}/file1.js`, `What goes in\n${folder}/file1.js.`, { + language: "javascript", +}) +def(`File ${folder}/file1.py`, `What goes in\n${folder}/file1.py.`, { + language: "python", +}) +def(`File /path_to_file/file2.md`, `What goes in\n/path_to_file/file2.md.`, { + language: "markdown", +}) + +$`You MUST specify a start_line and end_line to only update a specific part of a file: + +FILE ${folder}/file1.py: +\`\`\`python start_line=15 end_line=20 +Replace line range 15-20 in \n${folder}/file1.py +\`\`\` + +FILE ${folder}/file1.py: +\`\`\`python start_line=30 end_line=35 +Replace line range 30-35 in \n${folder}/file1.py +\`\`\` + +` + +$`- 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 start_line, end_line for large files with small updates` +if (folder !== ".") + $`When generating new files, place files in folder "${folder}".` +$`- If a file does not have changes, do not regenerate. +- Do NOT emit line numbers in file. +- CSV files are inlined as markdown tables.` diff --git a/packages/core/src/promptdom.ts b/packages/core/src/promptdom.ts index 296127c4f4..92d26fed7a 100644 --- a/packages/core/src/promptdom.ts +++ b/packages/core/src/promptdom.ts @@ -243,12 +243,19 @@ function renderDefNode(def: PromptDefNode): string { while (dfence && body.includes(dfence)) { dfence += "`" } + const diffFormat = + body.length > 500 + ? " preferred_output_format=CHANGELOG " + : body.length < 200 + ? " preferred_output_format=FILE " + : "" const res = (name ? name + ":\n" : "") + dfence + dtype + (file.filename ? ` file="${file.filename}"` : "") + (schema ? ` schema=${schema}` : "") + + diffFormat + "\n" + body + dfence + diff --git a/packages/core/src/systems.ts b/packages/core/src/systems.ts index adff8ac324..de4ce49da7 100644 --- a/packages/core/src/systems.ts +++ b/packages/core/src/systems.ts @@ -8,7 +8,7 @@ import { arrayify } from "./util" /** * Function to resolve and return a list of systems based on the provided script and project. * This function analyzes the script options and JavaScript source code to determine applicable systems. - * + * * @param prj - The project object containing templates and other project-related data. * @param script - An object containing options for the prompt system, model options, and optionally JavaScript source code. * @returns An array of unique system IDs that are applicable based on the analysis. @@ -45,6 +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.changelog") // Add file schema system if schema is used if (useSchema) systems.push("system.files_schema") } @@ -82,7 +83,7 @@ export function resolveSystems( /** * Helper function to resolve tools in the project and return their system IDs. * Finds systems in the project associated with a specific tool. - * + * * @param prj - The project object containing templates and other project-related data. * @param tool - The tool ID to resolve systems for. * @returns An array of system IDs associated with the specified tool. @@ -99,7 +100,7 @@ function resolveSystemFromTools(prj: Project, tool: string): string[] { /** * Function to resolve tools in the project based on provided systems and tools. * This function returns a list of tool objects with their IDs and descriptions. - * + * * @param prj - The project object containing templates and other project-related data. * @param systems - An array of system IDs to resolve tools for. * @param tools - An array of tool IDs to resolve tools for. 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/edits_files_diff.genai.mts b/packages/sample/src/edits/edits_files_diff.genai.mts index 485ad00163..2e782804da 100644 --- a/packages/sample/src/edits/edits_files_diff.genai.mts +++ b/packages/sample/src/edits/edits_files_diff.genai.mts @@ -14,3 +14,4 @@ script({ }) import { editTest } from "./fileedittest.mts" editTest() +//$`Use DIFF for changes in src/edits/su/fib.ts` diff --git a/packages/sample/src/edits/edits_tool.genai.mts b/packages/sample/src/edits/edits_tool.genai.mts new file mode 100644 index 0000000000..039761f300 --- /dev/null +++ b/packages/sample/src/edits/edits_tool.genai.mts @@ -0,0 +1,58 @@ +script({ + model: "large", + files: "src/edits/fibs/fib.*", + system: ["system"], + lineNumbers: true, + tests: [ + { + files: "src/edits/fibs/fib.*", + }, + { + files: "src/edits/bigfibs/fib.*", + }, + ], +}) +import { editTest } from "./fileedittest.mts" + +$`## File edits + +Use the 'file_edit' tool to update a file with new content. THIS IS IMPORTANT + +` + +editTest() + +defTool( + "file_edit", + "Updates a file with new content. If the file is large, use lineStart and lineEnd in multiple tool calls to split the update into multiple parts THIS IS VERY IMPORTANT.", + { + type: "object", + properties: { + filename: { + type: "string", + description: + "The path of the file to update relative to the workspace root", + }, + content: { + type: "string", + description: + "The new content to write to the file. Preserve white space.", + }, + lineStart: { + type: "number", + description: "The line number to start the edit", + }, + lineEnd: { + type: "number", + description: "The line number to end the edit", + }, + }, + required: ["filename", "content"], + }, + async (args) => { + const { context, filename, content, lineStart, lineEnd } = args + context.log(`${filename}#L${lineStart || ""}:${lineEnd || ""}`) + context.log(content) + return "ok" + } +) diff --git a/packages/sample/src/edits/fibs/fib.cpp b/packages/sample/src/edits/fibs/fib.cpp deleted file mode 100644 index 633c0c8e6b..0000000000 --- a/packages/sample/src/edits/fibs/fib.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include - -int fibonacci(int n) { - // TODO: implement fibonacci algorithm - return 0; // BODY -} // this one needs to go -// another comment 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 new file mode 100644 index 0000000000..6b090769de --- /dev/null +++ b/packages/sample/src/edits/su/fib.ts @@ -0,0 +1,374 @@ +const poems = [ + "Whispers of the wind, secrets untold.", + "Stars dance in the velvet night.", + "A single tear, a thousand stories.", + "Sunrise paints the sky with hope.", + "Moonlight kisses the silent sea.", + "Dreams woven in the fabric of time.", + "Echoes of laughter in the breeze.", + "Raindrops sing on the windowpane.", + "A fleeting moment, forever cherished.", + "Nature's symphony, a timeless tune.", + "Love's gentle touch, a heart's embrace.", + "Shadows play in the twilight glow.", + "A journey's end, a new beginning.", + "Whispers of love in the autumn air.", + "A silent promise, a whispered vow.", + "The scent of rain on a summer's day.", + "A fleeting glance, a lasting memory.", + "The dance of leaves in the autumn wind.", + "A single rose, a world of meaning.", + "The calm before the storm's embrace.", + "A gentle breeze, a whispered prayer.", + "The first snowflake, a winter's kiss.", + "A silent night, a star's embrace.", + "The warmth of the sun on a cold day.", + "A fleeting shadow, a lingering thought.", + "The sound of waves on a distant shore.", + "A moment of peace in a chaotic world.", + "The scent of flowers in the spring air.", + "A gentle touch, a heart's desire.", + "The whisper of leaves in the forest.", + "A single star in the midnight sky.", + "The promise of dawn in the darkest night.", + "A fleeting smile, a heart's delight.", + "The sound of laughter in the rain.", + "A silent wish upon a shooting star.", + "The warmth of a hug on a cold day.", + "A gentle rain on a summer's night.", + "The whisper of the wind in the trees.", + "A single moment, a lifetime of memories.", + "The scent of pine in the winter air.", + "A gentle wave on a tranquil sea.", + "The promise of spring in the winter chill.", + "A fleeting dream, a heart's desire.", + "The sound of footsteps in the snow.", + "A silent prayer in the moonlight.", + "The warmth of a fire on a cold night.", + "A gentle breeze on a summer's day.", + "The whisper of the ocean's song.", + "A single tear, a heart's release.", + "The promise of love in a single glance.", + "A fleeting moment, a heart's embrace.", + "The sound of music in the night.", + "A gentle touch, a soul's connection.", + "The whisper of the stars above.", + "A single heartbeat, a world of meaning.", + "The promise of tomorrow in a single breath.", + "A fleeting shadow, a heart's reflection.", + "The sound of silence in the night.", + "A gentle kiss, a heart's surrender.", + "The whisper of dreams in the night.", + "A single flame, a heart's warmth.", + "The promise of hope in a single smile.", + "A fleeting thought, a heart's whisper.", + "The sound of the wind in the trees.", + "A gentle rain, a heart's cleansing.", + "The whisper of love in the night.", + "A single star, a heart's guide.", + "The promise of peace in a single touch.", + "A fleeting moment, a heart's joy.", + "The sound of waves on the shore.", + "A gentle breeze, a heart's sigh.", + "The whisper of the night sky.", + "A single tear, a heart's release.", + "The promise of dawn in the night.", + "A fleeting smile, a heart's light.", + "The sound of rain on the roof.", + "A gentle touch, a heart's song.", + "The whisper of the wind's embrace.", + "A single heartbeat, a heart's rhythm.", + "The promise of love in the night.", + "A fleeting dream, a heart's hope.", + "The sound of laughter in the air.", + "A gentle kiss, a heart's promise.", + "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.", +] +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.", + "The sound of a heartbeat in the silence.", + "A gentle touch, a soul's whisper.", + "The promise of spring in the winter's chill.", + "A single tear, a heart's release.", + "The warmth of the sun on a winter's day.", + "A fleeting smile, a heart's delight.", + "The sound of rain on a tin roof.", + "A gentle breeze, a heart's sigh.", + "The whisper of the ocean's song.", + "A single star, a heart's guide.", + "The promise of love in a single glance.", + "A fleeting moment, a heart's embrace.", + "The sound of music in the night.", + "A gentle touch, a soul's connection.", + "The whisper of the stars above.", + "A single heartbeat, a world of meaning.", + "The promise of tomorrow in a single breath.", + "A fleeting shadow, a heart's reflection.", + "The sound of silence in the night.", + "A gentle kiss, a heart's surrender.", + "The whisper of dreams in the night.", + "A single flame, a heart's warmth.", + "The promise of hope in a single smile.", + "A fleeting thought, a heart's whisper.", + "The sound of the wind in the trees.", + "A gentle rain, a heart's cleansing.", + "The whisper of love in the night.", + "A single star, a heart's guide.", + "The promise of peace in a single touch.", + "A fleeting moment, a heart's joy.", + "The sound of waves on the shore.", + "A gentle breeze, a heart's sigh.", + "The whisper of the night sky.", + "A single tear, a heart's release.", + "The promise of dawn in the night.", + "A fleeting smile, a heart's light.", + "The sound of rain on the roof.", + "A gentle touch, a heart's song.", + "The whisper of the wind's embrace.", + "A single heartbeat, a heart's rhythm.", + "The promise of love in the night.", + "A fleeting dream, a heart's hope.", + "The sound of laughter in the air.", + "A gentle kiss, a heart's promise.", + "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 wind's song.", + "A single heartbeat, a heart's beat.", + "The promise of love in the dawn.", + "A fleeting dream, a heart's wish.", + "The sound of laughter in the breeze.", + "A gentle kiss, a heart's touch.", + "The whisper of the stars' light.", + "A single flame, a heart's glow.", + "The promise of tomorrow in the dusk.", + "A fleeting thought, a heart's muse.", + "The sound of silence in the dawn.", + "A gentle rain, a heart's wash.", + "The whisper of love's song.", + "A single star, a heart's light.", + "The promise of hope in the dusk.", + "A fleeting moment, a heart's beat.", + "The sound of waves in the dusk.", + "A gentle breeze, a heart's breath.", + "The whisper of the night sky.", + "A single tear, a heart's cry.", + "The promise of dawn in the dusk.", + "A fleeting smile, a heart's joy.", + "The sound of rain in the dusk.", + "A gentle touch, a heart's feel.", + "The whisper of the wind's breath.", + "A single heartbeat, a heart's pulse.", + "The promise of love in the dusk.", + "A fleeting dream, a heart's vision.", + "The sound of laughter in the dusk.", + "A gentle kiss, a heart's peck.", + "The whisper of the stars' glow.", + "A single flame, a heart's fire.", + "The promise of tomorrow in the dawn.", + "A fleeting thought, a heart's idea.", + "The sound of silence in the dusk.", + "A gentle rain, a heart's cleanse.", + "The whisper of love's touch.", +]