71 lines
2.1 KiB
TypeScript
71 lines
2.1 KiB
TypeScript
/**
|
||
* Template escaping and placeholder replacement utilities
|
||
*
|
||
* Used by instruction builders to process instruction_template content.
|
||
*/
|
||
|
||
import type { PieceMovement } from '../../models/types.js';
|
||
import type { InstructionContext } from './instruction-context.js';
|
||
|
||
/**
|
||
* Escape special characters in dynamic content to prevent template injection.
|
||
*/
|
||
export function escapeTemplateChars(str: string): string {
|
||
return str.replace(/\{/g, '{').replace(/\}/g, '}');
|
||
}
|
||
|
||
/**
|
||
* 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_iterations}, and {movement_iteration}
|
||
result = result.replace(/\{iteration\}/g, String(context.iteration));
|
||
result = result.replace(/\{max_iterations\}/g, String(context.maxIterations));
|
||
result = result.replace(/\{movement_iteration\}/g, String(context.movementIteration));
|
||
|
||
// Replace {previous_response}
|
||
if (step.passPreviousResponse) {
|
||
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;
|
||
}
|