fix: replan-slice infinite loop, non-standard finish_reason crash, fork-resilient test (#866)
This commit is contained in:
parent
2dd7e256f0
commit
5d86159ea8
2 changed files with 48 additions and 4 deletions
|
|
@ -747,10 +747,13 @@ function mapStopReason(reason: ChatCompletionChunk.Choice["finish_reason"]): Sto
|
|||
return "toolUse";
|
||||
case "content_filter":
|
||||
return "error";
|
||||
default: {
|
||||
const _exhaustive: never = reason;
|
||||
throw new Error(`Unhandled stop reason: ${_exhaustive}`);
|
||||
}
|
||||
default:
|
||||
// Third-party and community models (e.g. Qwen GGUF quants) may emit
|
||||
// non-standard finish_reason values like "eos_token", "eos", or
|
||||
// "end_of_turn". The OpenAI spec defines finish_reason as a string,
|
||||
// so we treat unrecognized values as a normal stop rather than
|
||||
// throwing — which would abort in-flight tool calls (#863).
|
||||
return "stop";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -493,4 +493,45 @@ console.log('\n=== doctor: no blocker → no blocker_discovered_no_replan issue
|
|||
rmSync(base, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// Artifact Resolution: resolveExpectedArtifactPath for replan-slice (#858)
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
import { resolveExpectedArtifactPath, verifyExpectedArtifact } from '../auto-recovery.ts';
|
||||
|
||||
console.log('\n=== artifact: resolveExpectedArtifactPath returns REPLAN.md path for replan-slice ===');
|
||||
{
|
||||
const base = createFixtureBase();
|
||||
writeRoadmap(base, 'M001', ROADMAP_ONE_SLICE);
|
||||
writePlan(base, 'M001', 'S01', makePlanT01DoneT02Pending());
|
||||
|
||||
const path = resolveExpectedArtifactPath('replan-slice', 'M001/S01', base);
|
||||
assertTrue(path !== null, 'resolveExpectedArtifactPath returns non-null for replan-slice');
|
||||
assertTrue(path!.endsWith('S01-REPLAN.md'), 'path ends with S01-REPLAN.md');
|
||||
rmSync(base, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
console.log('\n=== artifact: verifyExpectedArtifact fails when REPLAN.md missing (#858) ===');
|
||||
{
|
||||
const base = createFixtureBase();
|
||||
writeRoadmap(base, 'M001', ROADMAP_ONE_SLICE);
|
||||
writePlan(base, 'M001', 'S01', makePlanT01DoneT02Pending());
|
||||
|
||||
const result = verifyExpectedArtifact('replan-slice', 'M001/S01', base);
|
||||
assertEq(result, false, 'verifyExpectedArtifact returns false when REPLAN.md is missing');
|
||||
rmSync(base, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
console.log('\n=== artifact: verifyExpectedArtifact passes when REPLAN.md exists (#858) ===');
|
||||
{
|
||||
const base = createFixtureBase();
|
||||
writeRoadmap(base, 'M001', ROADMAP_ONE_SLICE);
|
||||
writePlan(base, 'M001', 'S01', makePlanT01DoneT02Pending());
|
||||
writeReplanFile(base, 'M001', 'S01', '# Replan\n\nBlocker addressed.');
|
||||
|
||||
const result = verifyExpectedArtifact('replan-slice', 'M001/S01', base);
|
||||
assertEq(result, true, 'verifyExpectedArtifact returns true when REPLAN.md exists');
|
||||
rmSync(base, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
report();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue