feat(engine): reviewer uses prompt layers for cross-session caching
This commit is contained in:
45
packages/engine/src/__tests__/reviewer-prompt-layers.test.ts
Normal file
45
packages/engine/src/__tests__/reviewer-prompt-layers.test.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { buildPromptLayers, collapsePromptLayers } from "../prompt-layers.js";
|
||||
|
||||
describe("reviewer prompt layering", () => {
|
||||
const REVIEWER_BASE = "You are an independent code and plan reviewer.";
|
||||
const MEMORY_INSTRUCTIONS = "\n## Memory\n\nUse fn_memory_search to look up context.";
|
||||
|
||||
it("puts base prompt + memory instructions in stable layer", () => {
|
||||
const layers = buildPromptLayers({
|
||||
basePrompt: REVIEWER_BASE + MEMORY_INSTRUCTIONS,
|
||||
agentInstructions: "Custom reviewer guidance.",
|
||||
pluginContributions: "## Plugin: lint\n\nCheck lint.",
|
||||
});
|
||||
|
||||
expect(layers.stable).toBe(REVIEWER_BASE + MEMORY_INSTRUCTIONS);
|
||||
expect(layers.stable).not.toContain("Custom reviewer guidance");
|
||||
expect(layers.stable).not.toContain("lint");
|
||||
});
|
||||
|
||||
it("produces identical stable layer across simulated sessions", () => {
|
||||
const layers1 = buildPromptLayers({
|
||||
basePrompt: REVIEWER_BASE + MEMORY_INSTRUCTIONS,
|
||||
agentInstructions: "Session 1 instructions.",
|
||||
});
|
||||
const layers2 = buildPromptLayers({
|
||||
basePrompt: REVIEWER_BASE + MEMORY_INSTRUCTIONS,
|
||||
agentInstructions: "Session 2 instructions.",
|
||||
});
|
||||
|
||||
expect(layers1.stable).toBe(layers2.stable);
|
||||
});
|
||||
|
||||
it("collapsed layers match legacy concatenation", () => {
|
||||
const layers = buildPromptLayers({
|
||||
basePrompt: REVIEWER_BASE,
|
||||
agentInstructions: "Check for bugs.",
|
||||
pluginContributions: "## Plugin: sec\n\nScan.",
|
||||
});
|
||||
const collapsed = collapsePromptLayers(layers);
|
||||
|
||||
expect(collapsed).toBe(
|
||||
`${REVIEWER_BASE}\n\n## Custom Instructions\n\nCheck for bugs.\n\n## Plugin: sec\n\nScan.`
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -18,9 +18,9 @@ import { reviewerLog } from "./logger.js";
|
||||
import { checkSessionError } from "./usage-limit-detector.js";
|
||||
import {
|
||||
resolveAgentInstructions,
|
||||
buildSystemPromptWithInstructions,
|
||||
buildPluginPromptSection,
|
||||
} from "./agent-instructions.js";
|
||||
import { buildPromptLayers, collapsePromptLayers } from "./prompt-layers.js";
|
||||
import { createFallbackModelObserver } from "./fallback-model-observer.js";
|
||||
import { createMemoryGetTool, createMemorySearchTool, createWebFetchTool } from "./agent-tools.js";
|
||||
|
||||
@@ -408,23 +408,27 @@ export async function reviewStep(
|
||||
const memorySection = options.rootDir && options.settings?.memoryEnabled !== false
|
||||
? "\n" + buildReviewerMemoryInstructions(options.rootDir, options.settings)
|
||||
: "";
|
||||
const reviewerSystemPrompt = buildSystemPromptWithInstructions(
|
||||
reviewerBasePrompt + memorySection,
|
||||
reviewerInstructions,
|
||||
);
|
||||
const reviewerContributions = options.pluginRunner
|
||||
?.getPromptContributionsForSurface("reviewer")
|
||||
?? [];
|
||||
if (reviewerContributions.length > 0) {
|
||||
reviewerLog.log(`applied ${reviewerContributions.length} plugin prompt contributions for reviewer surface`);
|
||||
}
|
||||
|
||||
// Build structured layers for cross-session prompt caching.
|
||||
// The stable layer (base prompt + memory instructions) is byte-identical
|
||||
// across all reviewer sessions in this task, enabling cache hits.
|
||||
const reviewerPluginContributions = buildPluginPromptSection(
|
||||
"reviewer",
|
||||
options.pluginRunner,
|
||||
);
|
||||
const reviewerSystemPromptFinal = reviewerPluginContributions
|
||||
? `${reviewerSystemPrompt}\n\n${reviewerPluginContributions}`
|
||||
: reviewerSystemPrompt;
|
||||
if (reviewerPluginContributions) {
|
||||
reviewerLog.log(`applied plugin prompt contributions for reviewer surface`);
|
||||
}
|
||||
|
||||
const layers = buildPromptLayers({
|
||||
basePrompt: reviewerBasePrompt + memorySection,
|
||||
agentInstructions: reviewerInstructions,
|
||||
pluginContributions: reviewerPluginContributions,
|
||||
});
|
||||
|
||||
// Collapsed string for backward compatibility with runtimes that don't
|
||||
// support layers (plugin runtimes, older pi versions).
|
||||
const reviewerSystemPromptFinal = collapsePromptLayers(layers);
|
||||
|
||||
// Build skill selection context (assigned agent skills take precedence over role fallback)
|
||||
let skillContext = undefined;
|
||||
@@ -495,6 +499,7 @@ export async function reviewStep(
|
||||
pluginRunner: options.pluginRunner,
|
||||
cwd,
|
||||
systemPrompt: reviewerSystemPromptFinal,
|
||||
systemPromptLayers: layers,
|
||||
tools: "readonly",
|
||||
customTools: [createWebFetchTool(), ...(memoryTools ?? [])],
|
||||
onText: agentLogger ? agentLogger.onText : (delta) => options.onText?.(delta),
|
||||
|
||||
Reference in New Issue
Block a user