refactor(agents): externalize prompts to versioned template files (Closes #24) - #101
Conversation
…amki#24) Signed-off-by: laurentketterle-hub <laurentketterle-hub@users.noreply.github.com>
…amki#24) Signed-off-by: laurentketterle-hub <laurentketterle-hub@users.noreply.github.com>
…amki#24) Signed-off-by: laurentketterle-hub <laurentketterle-hub@users.noreply.github.com>
…amki#24) Signed-off-by: laurentketterle-hub <laurentketterle-hub@users.noreply.github.com>
…amki#24) Signed-off-by: laurentketterle-hub <laurentketterle-hub@users.noreply.github.com>
…amki#24) Signed-off-by: laurentketterle-hub <laurentketterle-hub@users.noreply.github.com>
📝 WalkthroughWalkthroughThe change externalizes four agent prompts into versioned template files. It adds ChangesPrompt externalization
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/prompts/CHANGELOG.md (1)
1-12: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winFix the Prettier failure before merge.
The
lintjob fails forsrc/prompts/CHANGELOG.md. Runprettier --write src/prompts/CHANGELOG.mdand commit the formatted file.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/prompts/CHANGELOG.md` around lines 1 - 12, Format src/prompts/CHANGELOG.md with Prettier using the repository’s standard configuration, ensuring the file passes the lint job; commit the resulting formatting-only changes.Source: Pipeline failures
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/prompts/loader.js`:
- Around line 8-10: Update loadPrompt to validate the resolved filePath remains
contained within PROMPTS_DIR before readFileSync, rejecting traversal names such
as ../../outside/secret while preserving valid prompt loading and the existing
not-found behavior.
- Around line 12-13: Update the replacement loop in the prompt loader to pass a
replacer function to template.replaceAll for each variable token, ensuring
String(value) is inserted literally even when it contains replacement specifiers
such as $$$$.
---
Outside diff comments:
In `@src/prompts/CHANGELOG.md`:
- Around line 1-12: Format src/prompts/CHANGELOG.md with Prettier using the
repository’s standard configuration, ensuring the file passes the lint job;
commit the resulting formatting-only changes.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: c983a4c7-5255-46fa-ab94-7adb34d48a17
📒 Files selected for processing (6)
src/prompts/CHANGELOG.mdsrc/prompts/analysis.txtsrc/prompts/code.txtsrc/prompts/loader.jssrc/prompts/research.txtsrc/prompts/summary.txt
| export function loadPrompt(name, vars = {}) { | ||
| const filePath = join(PROMPTS_DIR, `${name}.txt`) | ||
| if (!existsSync(filePath)) throw new Error(`Prompt not found: ${name}.txt`) |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -nP -C 4 '\bloadPrompt\s*\(' \
--glob '*.js' --glob '*.mjs' --glob '*.cjs' --glob '*.ts' .Repository: Flamki/stellarmind
Length of output: 784
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== loader.js =="
cat -n src/prompts/loader.js
echo
echo "== prompt files =="
find src/prompts -maxdepth 1 -type f -print | sort | while read -r f; do
echo "--- $f"
sed -n '1,80p' "$f"
done
echo
echo "== imports of loader =="
rg -nP -C 3 '\.\/loader|loadPrompt\s*<|from\s+.*prompts|from "\.\/prompts/loader|from '\''\.\/prompts/loader|import\s*\(' --glob '*.js' --glob '*.mjs' --glob '*.cjs' --glob '*.ts' .Repository: Flamki/stellarmind
Length of output: 3237
Check that prompt names cannot leave PROMPTS_DIR.
loadPrompt joins name directly into a file path and reads the result. Add validation or a resolved-path containment check before readFileSync so names such as ../../outside/secret cannot select files outside src/prompts.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/prompts/loader.js` around lines 8 - 10, Update loadPrompt to validate the
resolved filePath remains contained within PROMPTS_DIR before readFileSync,
rejecting traversal names such as ../../outside/secret while preserving valid
prompt loading and the existing not-found behavior.
| for (const [key, value] of Object.entries(vars)) | ||
| template = template.replaceAll(`{{${key}}}`, String(value)) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg '(^|/)src/prompts/loader\.js$|loader\.js$' || true
echo "== loader.js =="
if [ -f src/prompts/loader.js ]; then
nl -ba src/prompts/loader.js | sed -n '1,120p'
fi
echo "== tests mentioning loader or prompt vars =="
rg -n "src/prompts/loader|prompts/loader|replaceAll\\(\\`\\{\\{.*\\}\\}\\`|replaceAll\\(.*\\{\\{|regression|token|\\$&|replacement" -S . --glob '!node_modules' --glob '!dist' --glob '!build' || true
echo "== JavaScript replacement behavior probe =="
node - <<'JS'
const inputs = [
{ template: 'hi {{x}}', vars: { x: '$&' } },
{ template: 'hi {{x}}', vars: { x: '$1' } },
{ template: 'hi {{x}} {{x}}', vars: { x: '$&x$&' } },
];
for (const { template, vars } of inputs) {
console.log('literal string:', template.replaceAll(`{{x}}`, String(vars.x)));
console.log('replacer function:', template.replaceAll(`{{x}}`, () => String(vars.x)));
}
JSRepository: Flamki/stellarmind
Length of output: 246
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== loader.js =="
if [ -f src/prompts/loader.js ]; then
cat -n src/prompts/loader.js | sed -n '1,160p'
fi
echo "== tests mentioning loader or prompt vars =="
rg -n "src/prompts/loader|prompts/loader|replaceAll\\(\\`\\{\\{.*\\}\\}\\`|replaceAll\\(.*\\{\\{|regression|token|\\$&|replacement|loader" -S . --glob '!node_modules' --glob '!dist' --glob '!build' || true
echo "== JavaScript replacement behavior probe =="
node - <<'JS'
const inputs = [
{ template: 'hi {{x}}', vars: { x: '$&' } },
{ template: 'hi {{x}}', vars: { x: '$1' } },
{ template: 'hi {{x}} {{x}}', vars: { x: '$&x$&' } },
];
for (const { template, vars } of inputs) {
console.log('literal string:', JSON.stringify(template.replaceAll(`{{x}}`, String(vars.x))));
console.log('replacer function:', JSON.stringify(template.replaceAll(`{{x}}`, () => String(vars.x))));
}
JSRepository: Flamki/stellarmind
Length of output: 5465
Insert variable values literally.
When value contains a replacement specifier such as $$$$, replaceAll can change the value it is meant to insert. Use a replacer function so the template token is replaced with the value unchanged.
Proposed fix
- template = template.replaceAll(`{{${key}}}`, String(value))
+ template = template.replaceAll(`{{${key}}}`, () => String(value))📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| for (const [key, value] of Object.entries(vars)) | |
| template = template.replaceAll(`{{${key}}}`, String(value)) | |
| for (const [key, value] of Object.entries(vars)) | |
| template = template.replaceAll(`{{${key}}}`, () => String(value)) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/prompts/loader.js` around lines 12 - 13, Update the replacement loop in
the prompt loader to pass a replacer function to template.replaceAll for each
variable token, ensuring String(value) is inserted literally even when it
contains replacement specifiers such as $$$$.
Summary
Externalizes agent prompts from embedded strings into versioned template files (Closes #24).
Files
src/prompts/research.txt,summary.txt,analysis.txt,code.txt— prompt templatessrc/prompts/loader.js—loadPrompt(name, vars)with{{variable}}substitutionsrc/prompts/CHANGELOG.md— version trackingUsage
Acceptance Criteria
src/prompts/.txtfiles extracted{{var}}substitution in loaderSigned-off-by: laurentketterle-hub laurentketterle-hub@users.noreply.github.com
Summary by CodeRabbit
New Features
Documentation