prompts: the shared formatting guide composes for practice too
The practice agent wrote wrong LaTeX delimiters — 40-formatting.md (the \(...\)/\[...\) delimiter law, markdown, mermaid) lived in shared/, which practice deliberately excluded. Owner ruling: formatting applies in every setting. Practice now composes its own directory plus a CURATED shared allowlist (40-formatting.md only — the question/ confidence/file mechanics stay out, practice has no such tools); the composition test pins the appendix and the order.
This commit is contained in:
@@ -34,6 +34,12 @@ import { FRAGMENT_RE, isValidSegmentPath, type PromptAgent, type PromptSegmentIn
|
|||||||
|
|
||||||
const PROMPTS_DIR = path.join(PATHS.root, "src", "agent", "prompts");
|
const PROMPTS_DIR = path.join(PATHS.root, "src", "agent", "prompts");
|
||||||
|
|
||||||
|
/** Shared fragments the PRACTICE agent composes (owner, 2026-10-04
|
||||||
|
* late): the formatting guide — LaTeX delimiters, markdown, mermaid —
|
||||||
|
* applies in every setting; the question/confidence/file mechanics do
|
||||||
|
* not (practice has no such tools). */
|
||||||
|
const PRACTICE_SHARED_FRAGMENTS = ["40-formatting.md"];
|
||||||
|
|
||||||
/** Absolute path for an override file (unchecked — validate first). */
|
/** Absolute path for an override file (unchecked — validate first). */
|
||||||
function overrideFileFor(segmentPath: string): string {
|
function overrideFileFor(segmentPath: string): string {
|
||||||
return path.join(PROMPTS_OVERRIDE_DIR, ...segmentPath.split("/"));
|
return path.join(PROMPTS_OVERRIDE_DIR, ...segmentPath.split("/"));
|
||||||
@@ -57,10 +63,12 @@ export function readPromptOverride(segmentPath: string): string | null {
|
|||||||
* method lead; the shared tool/file/format mechanics are an appendix).
|
* method lead; the shared tool/file/format mechanics are an appendix).
|
||||||
* The exact order composeInstructions composes them in. */
|
* The exact order composeInstructions composes them in. */
|
||||||
export function listSourceSegments(agent: PromptAgent): Array<{ path: string; shared: boolean; file: string }> {
|
export function listSourceSegments(agent: PromptAgent): Array<{ path: string; shared: boolean; file: string }> {
|
||||||
// PRACTICE (owner, 2026-10-04): its own directory ONLY — the practice
|
// PRACTICE (owner, 2026-10-04): its own directory plus a CURATED
|
||||||
// doctrine contradicts the teaching base and the shared question/
|
// shared appendix — the teaching base and the question/confidence/
|
||||||
// confidence mechanics; prompts/practice/00-base.md plays the base
|
// file mechanics stay out (the doctrine contradicts them; 00-base.md
|
||||||
// role (voice + accuracy), so nothing shared composes.
|
// plays the base role), but the FORMATTING guide composes for every
|
||||||
|
// agent (owner, 2026-10-04 late): LaTeX delimiters and markdown apply
|
||||||
|
// in all settings — practice must write \(...\)/\[...\] too.
|
||||||
const segments: Array<{ path: string; shared: boolean; file: string }> = agent === "practice" ? [] : [
|
const segments: Array<{ path: string; shared: boolean; file: string }> = agent === "practice" ? [] : [
|
||||||
{ path: "system-prompt.md", shared: true, file: PATHS.teacherPrompt },
|
{ path: "system-prompt.md", shared: true, file: PATHS.teacherPrompt },
|
||||||
];
|
];
|
||||||
@@ -71,9 +79,14 @@ export function listSourceSegments(agent: PromptAgent): Array<{ path: string; sh
|
|||||||
segments.push({ path: `${agent}/${f}`, shared: false, file: path.join(dir, f) });
|
segments.push({ path: `${agent}/${f}`, shared: false, file: path.join(dir, f) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const sharedDir = agent === "practice" ? null : path.join(PROMPTS_DIR, "shared");
|
const sharedDir = path.join(PROMPTS_DIR, "shared");
|
||||||
if (sharedDir && fs.existsSync(sharedDir)) {
|
if (fs.existsSync(sharedDir)) {
|
||||||
const sharedFragments = fs.readdirSync(sharedDir).filter((f) => FRAGMENT_RE.test(f)).sort();
|
// The practice allowlist (owner, 2026-10-04 late): formatting only.
|
||||||
|
const allow = agent === "practice" ? PRACTICE_SHARED_FRAGMENTS : null;
|
||||||
|
const sharedFragments = fs
|
||||||
|
.readdirSync(sharedDir)
|
||||||
|
.filter((f) => FRAGMENT_RE.test(f) && (allow === null || allow.includes(f)))
|
||||||
|
.sort();
|
||||||
for (const f of sharedFragments) {
|
for (const f of sharedFragments) {
|
||||||
segments.push({ path: `shared/${f}`, shared: true, file: path.join(sharedDir, f) });
|
segments.push({ path: `shared/${f}`, shared: true, file: path.join(sharedDir, f) });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,8 +153,8 @@ describe("the practice agent", () => {
|
|||||||
|
|
||||||
// ── the prompt composition ──────────────────────────────────────────────────
|
// ── the prompt composition ──────────────────────────────────────────────────
|
||||||
|
|
||||||
describe("practice prompt composition (own directory alone)", () => {
|
describe("practice prompt composition (own directory + the formatting appendix)", () => {
|
||||||
it("composes base + doctrine — never the teaching base or shared fragments", () => {
|
it("composes base + doctrine — never the teaching base or question/confidence mechanics", () => {
|
||||||
const prompt = composeInstructions("practice");
|
const prompt = composeInstructions("practice");
|
||||||
// The base's voice section and the doctrine's spine are present…
|
// The base's voice section and the doctrine's spine are present…
|
||||||
assert.match(prompt, /Everything in this section deletes a default/);
|
assert.match(prompt, /Everything in this section deletes a default/);
|
||||||
@@ -167,6 +167,13 @@ describe("practice prompt composition (own directory alone)", () => {
|
|||||||
assert.doesNotMatch(prompt, /predict/i);
|
assert.doesNotMatch(prompt, /predict/i);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("the SHARED formatting guide composes (owner, 2026-10-04 late): LaTeX delimiters in every setting", () => {
|
||||||
|
const prompt = composeInstructions("practice");
|
||||||
|
// The delimiter law — practice must write \(...\)/\[...\] too.
|
||||||
|
assert.match(prompt, /NEVER `\$` or `\$\$`/);
|
||||||
|
assert.ok(prompt.indexOf("# The practice session") < prompt.indexOf("## Formatting"), "formatting rides as the appendix");
|
||||||
|
});
|
||||||
|
|
||||||
it("base precedes doctrine (00- sorts before 10-)", () => {
|
it("base precedes doctrine (00- sorts before 10-)", () => {
|
||||||
const prompt = composeInstructions("practice");
|
const prompt = composeInstructions("practice");
|
||||||
assert.ok(prompt.indexOf("The agent") < prompt.indexOf("# The practice session"));
|
assert.ok(prompt.indexOf("The agent") < prompt.indexOf("# The practice session"));
|
||||||
|
|||||||
Reference in New Issue
Block a user