Merge pull request #3539 from Tibsfox/fix/inject-slice-context-into-prompts
fix(gsd): inject S##-CONTEXT.md from slice discussion into all prompt builders
This commit is contained in:
commit
5c7e5efcf4
2 changed files with 71 additions and 0 deletions
|
|
@ -994,10 +994,15 @@ export async function buildResearchSlicePrompt(
|
|||
const milestoneResearchPath = resolveMilestoneFile(base, mid, "RESEARCH");
|
||||
const milestoneResearchRel = relMilestoneFile(base, mid, "RESEARCH");
|
||||
|
||||
const sliceContextPath = resolveSliceFile(base, mid, sid, "CONTEXT");
|
||||
const sliceContextRel = relSliceFile(base, mid, sid, "CONTEXT");
|
||||
|
||||
const inlined: string[] = [];
|
||||
inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
|
||||
const contextInline = await inlineFileOptional(contextPath, contextRel, "Milestone Context");
|
||||
if (contextInline) inlined.push(contextInline);
|
||||
const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
|
||||
if (sliceCtxInline) inlined.push(sliceCtxInline);
|
||||
const researchInline = await inlineFileOptional(milestoneResearchPath, milestoneResearchRel, "Milestone Research");
|
||||
if (researchInline) inlined.push(researchInline);
|
||||
const decisionsInline = await inlineDecisionsFromDb(base, mid);
|
||||
|
|
@ -1045,6 +1050,8 @@ export async function buildPlanSlicePrompt(
|
|||
const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
|
||||
const researchPath = resolveSliceFile(base, mid, sid, "RESEARCH");
|
||||
const researchRel = relSliceFile(base, mid, sid, "RESEARCH");
|
||||
const sliceContextPath = resolveSliceFile(base, mid, sid, "CONTEXT");
|
||||
const sliceContextRel = relSliceFile(base, mid, sid, "CONTEXT");
|
||||
|
||||
const inlined: string[] = [];
|
||||
|
||||
|
|
@ -1053,6 +1060,8 @@ export async function buildPlanSlicePrompt(
|
|||
if (researchSliceAnchor) inlined.push(formatAnchorForPrompt(researchSliceAnchor));
|
||||
|
||||
inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
|
||||
const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
|
||||
if (sliceCtxInline) inlined.push(sliceCtxInline);
|
||||
const researchInline = await inlineFileOptional(researchPath, researchRel, "Slice Research");
|
||||
if (researchInline) inlined.push(researchInline);
|
||||
if (inlineLevel !== "minimal") {
|
||||
|
|
@ -1253,9 +1262,13 @@ export async function buildCompleteSlicePrompt(
|
|||
const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
|
||||
const slicePlanPath = resolveSliceFile(base, mid, sid, "PLAN");
|
||||
const slicePlanRel = relSliceFile(base, mid, sid, "PLAN");
|
||||
const sliceContextPath = resolveSliceFile(base, mid, sid, "CONTEXT");
|
||||
const sliceContextRel = relSliceFile(base, mid, sid, "CONTEXT");
|
||||
|
||||
const inlined: string[] = [];
|
||||
inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
|
||||
const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
|
||||
if (sliceCtxInline) inlined.push(sliceCtxInline);
|
||||
inlined.push(await inlineFile(slicePlanPath, slicePlanRel, "Slice Plan"));
|
||||
if (inlineLevel !== "minimal") {
|
||||
const requirementsInline = await inlineRequirementsFromDb(base, sid, inlineLevel);
|
||||
|
|
@ -1510,9 +1523,13 @@ export async function buildReplanSlicePrompt(
|
|||
const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
|
||||
const slicePlanPath = resolveSliceFile(base, mid, sid, "PLAN");
|
||||
const slicePlanRel = relSliceFile(base, mid, sid, "PLAN");
|
||||
const sliceContextPath = resolveSliceFile(base, mid, sid, "CONTEXT");
|
||||
const sliceContextRel = relSliceFile(base, mid, sid, "CONTEXT");
|
||||
|
||||
const inlined: string[] = [];
|
||||
inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
|
||||
const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
|
||||
if (sliceCtxInline) inlined.push(sliceCtxInline);
|
||||
inlined.push(await inlineFile(slicePlanPath, slicePlanRel, "Current Slice Plan"));
|
||||
|
||||
// Find the blocker task summary — the completed task with blocker_discovered: true
|
||||
|
|
@ -1627,9 +1644,13 @@ export async function buildReassessRoadmapPrompt(
|
|||
const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
|
||||
const summaryPath = resolveSliceFile(base, mid, completedSliceId, "SUMMARY");
|
||||
const summaryRel = relSliceFile(base, mid, completedSliceId, "SUMMARY");
|
||||
const sliceContextPath = resolveSliceFile(base, mid, completedSliceId, "CONTEXT");
|
||||
const sliceContextRel = relSliceFile(base, mid, completedSliceId, "CONTEXT");
|
||||
|
||||
const inlined: string[] = [];
|
||||
inlined.push(await inlineFile(roadmapPath, roadmapRel, "Current Roadmap"));
|
||||
const sliceCtxInline = await inlineFileOptional(sliceContextPath, sliceContextRel, "Slice Context (from discussion)");
|
||||
if (sliceCtxInline) inlined.push(sliceCtxInline);
|
||||
inlined.push(await inlineFile(summaryPath, summaryRel, `${completedSliceId} Summary`));
|
||||
if (inlineLevel !== "minimal") {
|
||||
const projectInline = await inlineProjectFromDb(base);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* Regression test: S##-CONTEXT.md from slice discussion must be
|
||||
* injected into all 5 downstream prompt builders (#3452).
|
||||
*
|
||||
* Scans auto-prompts.ts for the 5 builder functions and verifies
|
||||
* each one resolves and inlines the slice-level CONTEXT file.
|
||||
*/
|
||||
|
||||
import { describe, test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { join, dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const autoPromptsPath = join(__dirname, "..", "auto-prompts.ts");
|
||||
const source = readFileSync(autoPromptsPath, "utf-8");
|
||||
|
||||
const BUILDERS = [
|
||||
"buildResearchSlicePrompt",
|
||||
"buildPlanSlicePrompt",
|
||||
"buildCompleteSlicePrompt",
|
||||
"buildReplanSlicePrompt",
|
||||
"buildReassessRoadmapPrompt",
|
||||
];
|
||||
|
||||
describe("slice CONTEXT.md injection into prompt builders (#3452)", () => {
|
||||
for (const builder of BUILDERS) {
|
||||
test(`${builder} resolves slice CONTEXT file`, () => {
|
||||
// Find the function body
|
||||
const fnStart = source.indexOf(`export async function ${builder}`);
|
||||
assert.ok(fnStart !== -1, `${builder} should exist in auto-prompts.ts`);
|
||||
|
||||
// Get a reasonable chunk after the function start (enough to cover the inlining section)
|
||||
const chunk = source.slice(fnStart, fnStart + 3000);
|
||||
|
||||
// Must resolve the slice CONTEXT path
|
||||
assert.ok(
|
||||
chunk.includes('resolveSliceFile(base, mid,') && chunk.includes('"CONTEXT"'),
|
||||
`${builder} should call resolveSliceFile with "CONTEXT"`,
|
||||
);
|
||||
|
||||
// Must inline it with inlineFileOptional
|
||||
assert.ok(
|
||||
chunk.includes('Slice Context'),
|
||||
`${builder} should inline slice CONTEXT with a "Slice Context" label`,
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue