feat(helper): add --prompt-file option for experimental prompt variation
Add optional --prompt-file <path> argument to start-case-experiment-helper.cjs
that allows supplying an alternative reconstruction prompt file while
preserving the production JSON generation schema.
Requirements implemented:
- Reads UTF-8 prompt file (absolute path or relative to prompts/)
- Replaces {{SCENARIO}} placeholder with scenario text using existing convention
- Validates file exists and contains required placeholder
- Rejects --prompt-file with non-A conditions via clear error
- Only compatible with condition A (production structured-output contract)
- Zero production code changes; apparatus-only modification
- Preserves existing behavior for all conditions B-E without flag
- Does not activate schema variants or freeform handling
Verified: syntax check passes, no whitespace errors in diff.
This commit is contained in:
@@ -57,9 +57,36 @@ function readScenarioInput(argv) {
|
|||||||
async function runStartCaseExperiment(scenarioInput, experimentInstruction, options = {}) {
|
async function runStartCaseExperiment(scenarioInput, experimentInstruction, options = {}) {
|
||||||
const condition = options.condition;
|
const condition = options.condition;
|
||||||
const treatment = options.treatment;
|
const treatment = options.treatment;
|
||||||
|
let scenarioTextForPrompt = scenarioInput?.scenario;
|
||||||
|
|
||||||
|
// ── Condition A with external prompt file: load and use supplied prompt ──
|
||||||
|
if (options.promptFile && condition === "A") {
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
let resolvedPromptPath;
|
||||||
|
if (path.isAbsolute(options.promptFile)) {
|
||||||
|
resolvedPromptPath = options.promptFile;
|
||||||
|
} else {
|
||||||
|
resolvedPromptPath = path.join(PROJECT_ROOT, "prompts", options.promptFile);
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(resolvedPromptPath)) {
|
||||||
|
throw new Error(
|
||||||
|
`--prompt-file not found: ${resolvedPromptPath}. ` +
|
||||||
|
`Provide an absolute path or a prompt filename in the prompts/ directory.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const customPromptContent = fs.readFileSync(resolvedPromptPath, "utf8");
|
||||||
|
if (!customPromptContent.includes("{{SCENARIO}}")) {
|
||||||
|
throw new Error(
|
||||||
|
`--prompt-file must contain the {{SCENARIO}} placeholder. ` +
|
||||||
|
`File: ${resolvedPromptPath}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
scenarioTextForPrompt = customPromptContent.replace("{{SCENARIO}}", scenarioInput?.scenario ?? "");
|
||||||
|
}
|
||||||
|
|
||||||
// ── Condition B/C/D/E: load alt prompt (B/C question-free; D deconstruct-freeform; E investigability-first freeform) ──
|
// ── Condition B/C/D/E: load alt prompt (B/C question-free; D deconstruct-freeform; E investigability-first freeform) ──
|
||||||
let scenarioTextForPrompt = scenarioInput?.scenario;
|
scenarioTextForPrompt = scenarioInput?.scenario;
|
||||||
if ((condition === "B" || condition === "C" || condition === "D" || condition === "E") && typeof scenarioTextForPrompt === "string") {
|
if ((condition === "B" || condition === "C" || condition === "D" || condition === "E") && typeof scenarioTextForPrompt === "string") {
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
@@ -408,11 +435,25 @@ if (require.main === module) {
|
|||||||
throw new Error(`Treatment "${treatment}" is only valid with --condition D or E, not --condition ${condition}`);
|
throw new Error(`Treatment "${treatment}" is only valid with --condition D or E, not --condition ${condition}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Prompt-file selector: external reconstruction prompt for condition A ──
|
||||||
|
const promptFileArgIdx = process.argv.indexOf("--prompt-file");
|
||||||
|
let promptFile = null;
|
||||||
|
if (promptFileArgIdx !== -1 && promptFileArgIdx + 1 < process.argv.length) {
|
||||||
|
promptFile = process.argv[promptFileArgIdx + 1];
|
||||||
|
}
|
||||||
|
if (promptFile !== null && condition !== "A") {
|
||||||
|
throw new Error(
|
||||||
|
`--prompt-file is only compatible with --condition A. ` +
|
||||||
|
`Condition ${condition ?? "(none, defaults to A)"} selected.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const scenarioInput = readScenarioInput(process.argv);
|
const scenarioInput = readScenarioInput(process.argv);
|
||||||
const reconstructionOnly = process.argv.includes("--reconstruction-only");
|
const reconstructionOnly = process.argv.includes("--reconstruction-only");
|
||||||
const result = await runStartCaseExperiment(scenarioInput, experimentInstruction, {
|
const result = await runStartCaseExperiment(scenarioInput, experimentInstruction, {
|
||||||
reconstructionOnly,
|
reconstructionOnly,
|
||||||
condition,
|
condition,
|
||||||
|
promptFile,
|
||||||
treatment: (condition === "D" || condition === "E") ? treatment : undefined,
|
treatment: (condition === "D" || condition === "E") ? treatment : undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user