nrs 0d1da61d14
[draft] takt/284/implement-using-only-the-files (#296)
* feat: track project-level .takt/pieces in version control

* feat: track project-level takt facets for customizable resources

* chore: include project .takt/config.yaml in git-tracked subset

* takt: github-issue-284-faceted-prompting
2026-02-18 23:21:09 +09:00

75 lines
2.3 KiB
TypeScript

/**
* Template escaping and placeholder replacement utilities
*
* Used by instruction builders to process instruction_template content.
*
* escapeTemplateChars is re-exported from faceted-prompting.
* replaceTemplatePlaceholders is TAKT-specific and stays here.
*/
import type { PieceMovement } from '../../models/types.js';
import type { InstructionContext } from './instruction-context.js';
import { escapeTemplateChars } from '../../../faceted-prompting/index.js';
export { escapeTemplateChars } from '../../../faceted-prompting/index.js';
/**
* Replace template placeholders in the instruction_template body.
*
* These placeholders may still be used in instruction_template for
* special cases or legacy templates.
*/
export function replaceTemplatePlaceholders(
template: string,
step: PieceMovement,
context: InstructionContext,
): string {
let result = template;
// Replace {task}
result = result.replace(/\{task\}/g, escapeTemplateChars(context.task));
// Replace {iteration}, {max_movements}, and {movement_iteration}
result = result.replace(/\{iteration\}/g, String(context.iteration));
result = result.replace(/\{max_movements\}/g, String(context.maxMovements));
result = result.replace(/\{movement_iteration\}/g, String(context.movementIteration));
// Replace {previous_response}
if (step.passPreviousResponse) {
if (context.previousResponseText !== undefined) {
result = result.replace(
/\{previous_response\}/g,
escapeTemplateChars(context.previousResponseText),
);
} else if (context.previousOutput) {
result = result.replace(
/\{previous_response\}/g,
escapeTemplateChars(context.previousOutput.content),
);
} else {
result = result.replace(/\{previous_response\}/g, '');
}
}
// Replace {user_inputs}
const userInputsStr = context.userInputs.join('\n');
result = result.replace(
/\{user_inputs\}/g,
escapeTemplateChars(userInputsStr),
);
// Replace {report_dir}
if (context.reportDir) {
result = result.replace(/\{report_dir\}/g, context.reportDir);
}
// Replace {report:filename} with reportDir/filename
if (context.reportDir) {
result = result.replace(/\{report:([^}]+)\}/g, (_match, filename: string) => {
return `${context.reportDir}/${filename}`;
});
}
return result;
}