Deduplicate reviewer policy text by making workflow IR review seams the engine's built-in prompt source. - Move the canonical built-in reviewer prompt into core agent prompts and export seam prompt resolution helpers. - Resolve reviewer prompts from explicit role overrides first, then workflow IR review seams, with the built-in prompt as a fallback. - Update prompt cache and reviewer tests to cover single-source reviewer prompt behavior. - Add a patch changeset for the published Fusion package. Files changed: .../FN-6235-reviewer-prompt-single-source.md | 5 + packages/core/src/__tests__/agent-prompts.test.ts | 8 +- packages/core/src/agent-prompts.ts | 109 +++++++++-- packages/core/src/index.ts | 2 + packages/core/src/workflow-ir-resolver.ts | 31 ++- .../src/__tests__/prompt-cache-integration.test.ts | 10 +- .../reviewer-prompt-single-source.test.ts | 160 +++++++++++++++ packages/engine/src/__tests__/reviewer.test.ts | 97 ++++----- packages/engine/src/prompt-layers.ts | 2 +- packages/engine/src/reviewer.ts | 217 ++------------------- 10 files changed, 370 insertions(+), 271 deletions(-) Fusion-Task-Id: FN-6235 Fusion-Task-Lineage: 725932d1-2469-4507-a0f9-0946c83a1572
52 lines
2.0 KiB
TypeScript
52 lines
2.0 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { resolveAgentPrompt } from "@fusion/core";
|
|
import { buildPromptLayers, collapsePromptLayers, type SystemPromptLayers } from "../prompt-layers.js";
|
|
|
|
const DEFAULT_REVIEWER_PROMPT = resolveAgentPrompt("reviewer");
|
|
|
|
describe("cross-session prompt cache integration", () => {
|
|
const MEMORY_INSTRUCTIONS = "\n## Memory\n\nUse fn_memory_search to look up relevant context.";
|
|
|
|
function simulateReviewerSession(sessionIndex: number): SystemPromptLayers {
|
|
return buildPromptLayers({
|
|
basePrompt: DEFAULT_REVIEWER_PROMPT,
|
|
agentInstructions: `Session ${sessionIndex}: custom instructions that vary per agent.`,
|
|
memorySection: MEMORY_INSTRUCTIONS,
|
|
pluginContributions: sessionIndex % 2 === 0
|
|
? "## Plugin: lint\n\nCheck lint rules."
|
|
: "",
|
|
});
|
|
}
|
|
|
|
it("produces byte-identical stable prefixes across 10 reviewer sessions", () => {
|
|
const sessions = Array.from({ length: 10 }, (_, i) => simulateReviewerSession(i));
|
|
|
|
const stablePrefix = sessions[0].stable;
|
|
for (let i = 1; i < sessions.length; i++) {
|
|
expect(sessions[i].stable).toBe(stablePrefix);
|
|
}
|
|
});
|
|
|
|
it("dynamic layers vary across sessions as expected", () => {
|
|
const sessions = Array.from({ length: 5 }, (_, i) => simulateReviewerSession(i));
|
|
|
|
const uniqueDynamics = new Set(sessions.map((s) => s.dynamic));
|
|
expect(uniqueDynamics.size).toBeGreaterThan(1);
|
|
});
|
|
|
|
it("collapsed layers produce valid non-empty strings", () => {
|
|
const sessions = Array.from({ length: 5 }, (_, i) => simulateReviewerSession(i));
|
|
|
|
for (const session of sessions) {
|
|
const collapsed = collapsePromptLayers(session);
|
|
expect(collapsed.length).toBeGreaterThan(0);
|
|
expect(collapsed).toContain("independent code and plan reviewer");
|
|
}
|
|
});
|
|
|
|
it("stable prefix starts with the canonical default reviewer prompt", () => {
|
|
const layers = simulateReviewerSession(0);
|
|
expect(layers.stable.startsWith(DEFAULT_REVIEWER_PROMPT)).toBe(true);
|
|
});
|
|
});
|