/**
* Delivery & Distribution — system prompt builder (Std 5, cost-
* appropriate prompts inherited from Pillar 2). Same scoped-prompt
* machinery as every other agent.
*
* In the foundational rule set the Delivery agent never calls the
* LLM — dispatch is fully deterministic given a matched delivery rule
* and a registered channel. The builder exists for future SME-encoded
* rules that genuinely require LLM judgment (e.g. dynamic recipient
* inference from a free-text audience descriptor).
*/
import { STANDARDS_SUMMARY, type PromptScope } from '../../../standards.js';
import {
AGENT_NAME,
AGENT_VERSION,
deliveryDistributionContract,
deliveryDistributionMatrix,
} from './matrix.js';
interface OpPrinciple { readonly n: number; readonly text: string; }
const OPERATING_PRINCIPLES: readonly OpPrinciple[] = [
{ n: 1, text: 'deliver only. Do NOT re-interpret or re-render — those are siblings\' jobs.' },
{ n: 3, text: 'every delivery decision (channel, cadence, addressing) traces to a declared delivery rule.' },
{ n: 4, text: 'no delivery outside approved channels. No delivery exceeding cadence policies. No silent dropping of failed dispatches.' },
{ n: 5, text: 'query find_rules(type="delivery", agent="delivery") with the visualization\'s audienceTier and any carry-through severity as triggers. Look up channels from the channel registry; never invent.' },
{ n: 6, text: 'cost-appropriate execution: dispatch is fully deterministic in the foundational rule set. LLM only when a rule explicitly requires judgment.' },
{ n: 7, text: 'per-dispatch confidence reflects fallback channel usage or acknowledgment-pending state.' },
{ n: 8, text: 'flag delivery failures, cadence violations, recipient-verification failures, and material-impact carry-through explicitly.' },
{ n: 9, text: 'escalations route to operations-reviewer (delivery / channel issues), compliance-reviewer (disclosure concerns), authorizing-decision-maker (material findings).' },
{ n: 12, text: 'persistent failures escalate; never silently drop a dispatch — every attempt is logged.' },
{ n: 0, text: 'Decision-forbidden: do not re-analyze findings, do not re-render visualizations, do not invent channels, do not exceed declared cadence, do not bypass disclosure.' },
];
function renderUniversal(engaged?: readonly number[]): string {
const set = engaged && engaged.length > 0 ? new Set(engaged) : null;
return STANDARDS_SUMMARY
.filter(s => !set || set.has(s.n))
.map(s => `${s.n}. ${s.name} — ${s.gist}`)
.join('\n');
}
function renderMatrix(): string {
return Object.entries(deliveryDistributionMatrix)
.map(([key, value]) => `${key.split('_')[0]}. ${value}`)
.join('\n');
}
function renderRunbook(): string {
return deliveryDistributionContract.runbook
.map(s => ` ${s.n}. ${s.name} — ${s.description}`)
.join('\n');
}
function renderPrinciples(engaged?: readonly number[]): string {
const set = engaged && engaged.length > 0 ? new Set(engaged) : null;
return OPERATING_PRINCIPLES
.filter(p => p.n === 0 || !set || set.has(p.n))
.map(p => (p.n === 0 ? `- ${p.text}` : `- Std ${p.n}: ${p.text}`))
.join('\n');
}
export function buildSystemPrompt(scope?: PromptScope): string {
const engaged = scope?.engagedStandards;
const isScoped = !!(engaged && engaged.length > 0);
const omitMatrix = scope?.omitMatrix ?? isScoped;
const omitRunbook = scope?.omitRunbook ?? isScoped;
const lines: string[] = [
`You are the ${AGENT_NAME} agent (v${AGENT_VERSION}) — the third agent of the BID Decision pillar and the framework\'s exit point.`,
];
if (isScoped) {
lines.push(
`All 12 universal operational standards govern your behavior. ` +
(scope?.stepLabel ? `Current step: "${scope.stepLabel}". ` : '') +
`Standards directly engaged by this step:`,
renderUniversal(engaged),
);
} else {
lines.push(
`Your operation is bounded by the 12 universal operational standards plus your per-agent matrix row.`,
``,
`## Universal standards`,
renderUniversal(),
);
}
if (!omitMatrix) {
lines.push(``, `## Your matrix row`, renderMatrix());
}
if (!omitRunbook) {
lines.push(``, `## Your runbook (Std 6)`, renderRunbook());
}
lines.push(``, `## Operating principles`, renderPrinciples(engaged));
return lines.join('\n');
}