interactive の選択肢が非同期実行時に出てしまうバグのfix

This commit is contained in:
nrslib 2026-02-13 23:28:20 +09:00
parent 54e9f80a57
commit 6fe8fece91
2 changed files with 27 additions and 6 deletions

View File

@ -10,6 +10,7 @@ export interface JudgeStatusOptions {
cwd: string; cwd: string;
movementName: string; movementName: string;
language?: Language; language?: Language;
interactive?: boolean;
} }
export interface JudgeStatusResult { export interface JudgeStatusResult {
@ -98,6 +99,14 @@ export async function judgeStatus(
return { ruleIndex: 0, method: 'auto_select' }; return { ruleIndex: 0, method: 'auto_select' };
} }
const interactiveEnabled = options.interactive === true;
const isValidRuleIndex = (index: number): boolean => {
if (index < 0 || index >= rules.length) return false;
const rule = rules[index];
return !(rule?.interactiveOnly && !interactiveEnabled);
};
const agentOptions = { const agentOptions = {
cwd: options.cwd, cwd: options.cwd,
maxTurns: 3, maxTurns: 3,
@ -115,7 +124,7 @@ export async function judgeStatus(
const stepNumber = structuredResponse.structuredOutput?.step; const stepNumber = structuredResponse.structuredOutput?.step;
if (typeof stepNumber === 'number' && Number.isInteger(stepNumber)) { if (typeof stepNumber === 'number' && Number.isInteger(stepNumber)) {
const ruleIndex = stepNumber - 1; const ruleIndex = stepNumber - 1;
if (ruleIndex >= 0 && ruleIndex < rules.length) { if (isValidRuleIndex(ruleIndex)) {
return { ruleIndex, method: 'structured_output' }; return { ruleIndex, method: 'structured_output' };
} }
} }
@ -126,16 +135,25 @@ export async function judgeStatus(
if (tagResponse.status === 'done') { if (tagResponse.status === 'done') {
const tagRuleIndex = detectRuleIndex(tagResponse.content, options.movementName); const tagRuleIndex = detectRuleIndex(tagResponse.content, options.movementName);
if (tagRuleIndex >= 0 && tagRuleIndex < rules.length) { if (isValidRuleIndex(tagRuleIndex)) {
return { ruleIndex: tagRuleIndex, method: 'phase3_tag' }; return { ruleIndex: tagRuleIndex, method: 'phase3_tag' };
} }
} }
// Stage 3: AI judge // Stage 3: AI judge
const conditions = rules.map((rule, index) => ({ index, text: rule.condition })); const conditions = rules
.map((rule, index) => ({ rule, index }))
.filter(({ rule }) => interactiveEnabled || !rule.interactiveOnly)
.map(({ index, rule }) => ({ index, text: rule.condition }));
if (conditions.length > 0) {
const fallbackIndex = await evaluateCondition(structuredInstruction, conditions, { cwd: options.cwd }); const fallbackIndex = await evaluateCondition(structuredInstruction, conditions, { cwd: options.cwd });
if (fallbackIndex >= 0 && fallbackIndex < rules.length) { if (fallbackIndex >= 0 && fallbackIndex < conditions.length) {
return { ruleIndex: fallbackIndex, method: 'ai_judge' }; const originalIndex = conditions[fallbackIndex]?.index;
if (originalIndex !== undefined) {
return { ruleIndex: originalIndex, method: 'ai_judge' };
}
}
} }
throw new Error(`Status not found for movement "${options.movementName}"`); throw new Error(`Status not found for movement "${options.movementName}"`);

View File

@ -36,6 +36,7 @@ function buildBaseContext(
if (reports.length > 0) { if (reports.length > 0) {
return { return {
language: ctx.language, language: ctx.language,
interactive: ctx.interactive,
reportContent: reports.join('\n\n---\n\n'), reportContent: reports.join('\n\n---\n\n'),
inputSource: 'report', inputSource: 'report',
}; };
@ -46,6 +47,7 @@ function buildBaseContext(
return { return {
language: ctx.language, language: ctx.language,
interactive: ctx.interactive,
lastResponse: ctx.lastResponse, lastResponse: ctx.lastResponse,
inputSource: 'response', inputSource: 'response',
}; };
@ -89,6 +91,7 @@ export async function runStatusJudgmentPhase(
cwd: ctx.cwd, cwd: ctx.cwd,
movementName: step.name, movementName: step.name,
language: ctx.language, language: ctx.language,
interactive: ctx.interactive,
}); });
const tag = `[${step.name.toUpperCase()}:${result.ruleIndex + 1}]`; const tag = `[${step.name.toUpperCase()}:${result.ruleIndex + 1}]`;
ctx.onPhaseComplete?.(step, 3, 'judge', tag, 'done'); ctx.onPhaseComplete?.(step, 3, 'judge', tag, 'done');