feat(engine): triage and heartbeat use prompt layers for caching

This commit is contained in:
Matthew Greenberg
2026-05-08 20:06:20 -04:00
parent 3ec6990457
commit d2eeabd5be
2 changed files with 33 additions and 32 deletions

View File

@@ -26,10 +26,10 @@ import { createTaskCreateTool, createTaskLogToolWithContext, createTaskDocumentW
import { AgentLogger } from "./agent-logger.js"; import { AgentLogger } from "./agent-logger.js";
import { import {
resolveAgentInstructionsWithRatings, resolveAgentInstructionsWithRatings,
buildSystemPromptWithInstructions,
buildPluginPromptSection, buildPluginPromptSection,
resolveAgentHeartbeatProcedure, resolveAgentHeartbeatProcedure,
} from "./agent-instructions.js"; } from "./agent-instructions.js";
import { buildPromptLayers, collapsePromptLayers } from "./prompt-layers.js";
import { heartbeatLog, formatError } from "./logger.js"; import { heartbeatLog, formatError } from "./logger.js";
import { createRunAuditor, type EngineRunContext } from "./run-audit.js"; import { createRunAuditor, type EngineRunContext } from "./run-audit.js";
import { promptWithFallback } from "./pi.js"; import { promptWithFallback } from "./pi.js";
@@ -1838,23 +1838,22 @@ export class HeartbeatMonitor {
} }
} }
const systemPrompt = buildSystemPromptWithInstructions( // Build structured layers for cross-session prompt caching.
baseHeartbeatSystemPrompt,
[resolvedInstructionsForIdentity, memoryInstructions, selfImprovePrompt].filter((part) => part.trim()).join("\n\n"),
);
const heartbeatContributions = this.pluginRunner
?.getPromptContributionsForSurface("heartbeat")
?? [];
if (heartbeatContributions.length > 0) {
heartbeatLog.log(`applied ${heartbeatContributions.length} plugin prompt contributions for heartbeat surface`);
}
const heartbeatPluginContributions = buildPluginPromptSection( const heartbeatPluginContributions = buildPluginPromptSection(
"heartbeat", "heartbeat",
this.pluginRunner, this.pluginRunner,
); );
const systemPromptFinal = heartbeatPluginContributions if (heartbeatPluginContributions) {
? `${systemPrompt}\n\n${heartbeatPluginContributions}` heartbeatLog.log(`applied plugin prompt contributions for heartbeat surface`);
: systemPrompt; }
const heartbeatLayers = buildPromptLayers({
basePrompt: baseHeartbeatSystemPrompt,
agentInstructions: [resolvedInstructionsForIdentity, memoryInstructions, selfImprovePrompt].filter((part) => part.trim()).join("\n\n"),
pluginContributions: heartbeatPluginContributions,
});
const systemPromptFinal = collapsePromptLayers(heartbeatLayers);
// fn_heartbeat_done must be the last tool in the array (stable terminal signal) // fn_heartbeat_done must be the last tool in the array (stable terminal signal)
heartbeatTools.push(heartbeatDoneTool); heartbeatTools.push(heartbeatDoneTool);
@@ -1948,6 +1947,7 @@ export class HeartbeatMonitor {
pluginRunner: this.pluginRunner, pluginRunner: this.pluginRunner,
cwd: rootDir, cwd: rootDir,
systemPrompt: systemPromptFinal, systemPrompt: systemPromptFinal,
systemPromptLayers: heartbeatLayers,
tools: "coding", tools: "coding",
customTools: heartbeatTools, customTools: heartbeatTools,
defaultProvider: heartbeatSessionModels.defaultProvider, defaultProvider: heartbeatSessionModels.defaultProvider,

View File

@@ -30,9 +30,9 @@ import { AgentLogger } from "./agent-logger.js";
import { import {
resolveAgentInstructions, resolveAgentInstructions,
resolveAgentInstructionsWithRatings, resolveAgentInstructionsWithRatings,
buildSystemPromptWithInstructions,
buildPluginPromptSection, buildPluginPromptSection,
} from "./agent-instructions.js"; } from "./agent-instructions.js";
import { buildPromptLayers, collapsePromptLayers } from "./prompt-layers.js";
import { createFallbackModelObserver } from "./fallback-model-observer.js"; import { createFallbackModelObserver } from "./fallback-model-observer.js";
import { planLog, reviewerLog, formatError } from "./logger.js"; import { planLog, reviewerLog, formatError } from "./logger.js";
import { import {
@@ -1014,30 +1014,29 @@ export class TriageProcessor {
const triageIdentitySection = assignedAgent const triageIdentitySection = assignedAgent
? `## Identity\n\nYou are ${assignedAgent.name}${assignedAgent.title?.trim() ? `, ${assignedAgent.title.trim()}` : ""} (agent ID: ${assignedAgent.id}, role: ${assignedAgent.role}).` ? `## Identity\n\nYou are ${assignedAgent.name}${assignedAgent.title?.trim() ? `, ${assignedAgent.title.trim()}` : ""} (agent ID: ${assignedAgent.id}, role: ${assignedAgent.role}).`
: ""; : "";
const triageSystemPrompt = buildSystemPromptWithInstructions( // Build structured layers for cross-session prompt caching.
resolveAgentPrompt("triage", settings.agentPrompts) const triagePluginContributions = buildPluginPromptSection(
"triage",
this.options.pluginRunner,
);
if (triagePluginContributions) {
planLog.log(`${task.id}: applied plugin prompt contributions for triage surface`);
}
const triageLayers = buildPromptLayers({
basePrompt: resolveAgentPrompt("triage", settings.agentPrompts)
|| (isFast ? FAST_TRIAGE_SYSTEM_PROMPT : TRIAGE_SYSTEM_PROMPT), || (isFast ? FAST_TRIAGE_SYSTEM_PROMPT : TRIAGE_SYSTEM_PROMPT),
[ agentInstructions: [
triageIdentitySection, triageIdentitySection,
triageInstructions, triageInstructions,
isResearchToolSurfaceEnabled(settings) isResearchToolSurfaceEnabled(settings)
? getResearchGuidanceForSurface("triage") ? getResearchGuidanceForSurface("triage")
: "", : "",
].filter((section) => section.trim()).join("\n\n"), ].filter((section) => section.trim()).join("\n\n"),
); pluginContributions: triagePluginContributions,
const triageContributions = this.options.pluginRunner });
?.getPromptContributionsForSurface("triage")
?? []; const triageSystemPromptFinal = collapsePromptLayers(triageLayers);
if (triageContributions.length > 0) {
planLog.log(`${task.id}: applied ${triageContributions.length} plugin prompt contributions for triage surface`);
}
const triagePluginContributions = buildPluginPromptSection(
"triage",
this.options.pluginRunner,
);
const triageSystemPromptFinal = triagePluginContributions
? `${triageSystemPrompt}\n\n${triagePluginContributions}`
: triageSystemPrompt;
// Build skill selection context (assigned agent skills take precedence over role fallback) // Build skill selection context (assigned agent skills take precedence over role fallback)
const skillContext = await buildSessionSkillContext({ const skillContext = await buildSessionSkillContext({
@@ -1054,6 +1053,7 @@ export class TriageProcessor {
pluginRunner: this.options.pluginRunner, pluginRunner: this.options.pluginRunner,
cwd: this.rootDir, cwd: this.rootDir,
systemPrompt: triageSystemPromptFinal, systemPrompt: triageSystemPromptFinal,
systemPromptLayers: triageLayers,
tools: "coding", tools: "coding",
customTools, customTools,
onText: agentLogger.onText, onText: agentLogger.onText,
@@ -1294,6 +1294,7 @@ export class TriageProcessor {
pluginRunner: this.options.pluginRunner, pluginRunner: this.options.pluginRunner,
cwd: this.rootDir, cwd: this.rootDir,
systemPrompt: triageSystemPromptFinal, systemPrompt: triageSystemPromptFinal,
systemPromptLayers: triageLayers,
tools: "coding", tools: "coding",
customTools, customTools,
onText: agentLogger.onText, onText: agentLogger.onText,