takt/src/core/piece/instruction/ReportInstructionBuilder.ts
nrslib 2c7bd4834f Faceted Prompting リネーム: stances→policies, report_formats→output_contracts
5つの関心を Persona, Policy, Instruction, Knowledge, Output Contract に統一。
ディレクトリ、YAMLキー、ソースコード、テンプレート、テスト、ドキュメントを全面更新。
2026-02-07 20:04:09 +09:00

100 lines
3.2 KiB
TypeScript

/**
* Phase 2 instruction builder (report output)
*
* Builds the instruction for the report output phase.
* Assembles template variables and renders a single complete template.
*/
import type { PieceMovement, Language } from '../../models/types.js';
import type { InstructionContext } from './instruction-context.js';
import { replaceTemplatePlaceholders } from './escape.js';
import { isReportObjectConfig, renderReportContext, renderReportOutputInstruction } from './InstructionBuilder.js';
import { loadTemplate } from '../../../shared/prompts/index.js';
/**
* Context for building report phase instruction.
*/
export interface ReportInstructionContext {
/** Working directory */
cwd: string;
/** Report directory path */
reportDir: string;
/** Movement iteration (for {movement_iteration} replacement) */
movementIteration: number;
/** Language */
language?: Language;
/** Target report file name (when generating a single report) */
targetFile?: string;
}
/**
* Builds Phase 2 (report output) instructions.
*
* Renders a single complete template with all variables.
*/
export class ReportInstructionBuilder {
constructor(
private readonly step: PieceMovement,
private readonly context: ReportInstructionContext,
) {}
build(): string {
if (!this.step.report) {
throw new Error(`ReportInstructionBuilder called for movement "${this.step.name}" which has no report config`);
}
const language = this.context.language ?? 'en';
// Build report context for Piece Context section
let reportContext: string;
if (this.context.targetFile) {
reportContext = `- Report Directory: ${this.context.reportDir}/\n- Report File: ${this.context.reportDir}/${this.context.targetFile}`;
} else {
reportContext = renderReportContext(this.step.report, this.context.reportDir);
}
// Build report output instruction
let reportOutput = '';
let hasReportOutput = false;
const instrContext: InstructionContext = {
task: '',
iteration: 0,
maxIterations: 0,
movementIteration: this.context.movementIteration,
cwd: this.context.cwd,
projectCwd: this.context.cwd,
userInputs: [],
reportDir: this.context.reportDir,
language,
};
if (isReportObjectConfig(this.step.report) && this.step.report.order) {
reportOutput = replaceTemplatePlaceholders(this.step.report.order.trimEnd(), this.step, instrContext);
hasReportOutput = true;
} else if (!this.context.targetFile) {
const output = renderReportOutputInstruction(this.step, instrContext, language);
if (output) {
reportOutput = output;
hasReportOutput = true;
}
}
// Build output contract
let outputContract = '';
let hasOutputContract = false;
if (isReportObjectConfig(this.step.report) && this.step.report.format) {
outputContract = replaceTemplatePlaceholders(this.step.report.format.trimEnd(), this.step, instrContext);
hasOutputContract = true;
}
return loadTemplate('perform_phase2_message', language, {
workingDirectory: this.context.cwd,
reportContext,
hasReportOutput,
reportOutput,
hasOutputContract,
outputContract,
});
}
}