evaluateProTurnCompletion's active-reasoning veto only treats a node as "still reasoning" when both conditions hold:
(message.content?.content_type === "thoughts" ||
message.content?.content_type === "code") &&
message.metadata?.reasoning_status === "is_reasoning"
(src/pro-final.ts, current main at 12ed925a5.)
If a resumed-reasoning node carries reasoning_status: "is_reasoning" but a content_type other than thoughts/code, the veto doesn't see it. A terminal-shaped interim text produced before that node then passes every other check (reasoning_ended precedes it, it is the only terminal leaf) and gets returned as {done: true, ...} — a false-positive terminal on a mid-reasoning progress text.
This reproduces the exact failure the function's design comment says it exists to prevent: "Pro can emit several short progress texts carrying both flags and then resume reasoning."
Reproduction
A mapping with:
recap(reasoning_ended)
-> terminal-shaped interim text
-> resumed reasoning {
content_type: "reasoning",
reasoning_status: "is_reasoning"
}
Current result (executed against a logic-identical plain-Node port of pro-final.ts):
{
"done": true,
"finalText": "Quick take: looks fine at a glance.",
"finalMessageId": "msg-interim",
"modelSlug": "gpt-5-6-pro",
"finishReason": "stop"
}
Expected: done: false.
Suggested fix
const activeReasoning = turnMessages.filter(
({ message }) => message.metadata?.reasoning_status === "is_reasoning",
);
That is deliberately more conservative: reasoning_status is the state signal; content_type names the node kind. Dropping the kind allowlist prevents new/renamed reasoning node types from failing open. It may reject additional ambiguous mappings (safe false negatives), but it cannot newly accept an in-progress turn.
I reproduced this red/green in a Vitest regression: the test fails before the one-line change (expected true to be false) and passes after. Happy to open a small PR with the fix and regression test if useful.
evaluateProTurnCompletion's active-reasoning veto only treats a node as "still reasoning" when both conditions hold:(
src/pro-final.ts, currentmainat12ed925a5.)If a resumed-reasoning node carries
reasoning_status: "is_reasoning"but acontent_typeother thanthoughts/code, the veto doesn't see it. A terminal-shaped interim text produced before that node then passes every other check (reasoning_endedprecedes it, it is the only terminal leaf) and gets returned as{done: true, ...}— a false-positive terminal on a mid-reasoning progress text.This reproduces the exact failure the function's design comment says it exists to prevent: "Pro can emit several short progress texts carrying both flags and then resume reasoning."
Reproduction
A mapping with:
Current result (executed against a logic-identical plain-Node port of
pro-final.ts):{ "done": true, "finalText": "Quick take: looks fine at a glance.", "finalMessageId": "msg-interim", "modelSlug": "gpt-5-6-pro", "finishReason": "stop" }Expected:
done: false.Suggested fix
That is deliberately more conservative:
reasoning_statusis the state signal;content_typenames the node kind. Dropping the kind allowlist prevents new/renamed reasoning node types from failing open. It may reject additional ambiguous mappings (safe false negatives), but it cannot newly accept an in-progress turn.I reproduced this red/green in a Vitest regression: the test fails before the one-line change (
expected true to be false) and passes after. Happy to open a small PR with the fix and regression test if useful.