chore: version up to 2.80.38 and package with refined recovery
This commit is contained in:
@@ -125,8 +125,36 @@ export function shouldFinalOnlyRetry(cleaned: CleanedAssistantOutput): boolean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we silently continue from where the answer was cut off? Only when it actually hit the
|
||||
* output-token ceiling and we already have a non-trivial visible answer to continue from.
|
||||
* Does the answer plainly end mid-sentence / mid-structure? Conservative — only flags *unambiguous*
|
||||
* incompleteness (a complete Korean sentence may legitimately end without a period, so we never flag
|
||||
* a plain syllable like `다`/`요`; we only flag connective particles, mid-English-words, mid-clause
|
||||
* commas/colons, unclosed code fences/brackets, and dangling markdown bullets/headings).
|
||||
*/
|
||||
export function looksCutOff(text: string): boolean {
|
||||
const t = (text || '').replace(/\s+$/, '');
|
||||
if (t.length < 12) return false;
|
||||
// unclosed code fence
|
||||
if ((t.match(/```/g) || []).length % 2 === 1) return true;
|
||||
// ends with an opening bracket / quote (unclosed pair)
|
||||
if (/[([{“‘"'`]$/.test(t)) return true;
|
||||
// dangling markdown bullet / heading / blockquote with no content after the marker
|
||||
if (/(?:^|\n)\s*(?:[-*+]|#{1,6}|>|\d+\.)\s*$/.test(t)) return true;
|
||||
// ends mid-English-word or mid-number
|
||||
if (/[A-Za-z0-9]$/.test(t)) return true;
|
||||
// ends mid-clause (comma / colon / semicolon / list separator)
|
||||
if (/[,:;·、,]$/.test(t)) return true;
|
||||
// ends with a Korean particle / connective ending that NEVER closes a sentence
|
||||
if (/(?:으로|로서|로써|로|의|에서|에게|한테|에|을|를|과|와|이랑|랑|는|은|이|가|도|만|까지|부터|마다|조차|마저|밖에|뿐|처럼|같이|보다|이나|거나|든지|든가|고|며|면서|면|어서|아서|여서|니까|는데|은데|ㄴ데|지만|던|도록)$/.test(t)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we silently continue from where the answer was cut off? The point is to recover regardless
|
||||
* of *why* it stopped, since local engines / SDKs often report the stop reason wrongly or not at all:
|
||||
* - the engine said it hit the output cap (`output-limit`), OR
|
||||
* - it generated close to the cap (a complete answer wouldn't dangle that early), OR
|
||||
* - the visible answer plainly ends mid-sentence and the engine didn't give a clean "done" reason.
|
||||
* Never continues from a too-short fragment, and never from a clean ending (terminal punctuation).
|
||||
*/
|
||||
export function shouldAutoContinue(
|
||||
stopKind: GenerationStopKind,
|
||||
@@ -134,10 +162,14 @@ export function shouldAutoContinue(
|
||||
outputTokens: number,
|
||||
maxOutputTokens: number
|
||||
): boolean {
|
||||
if (stopKind !== 'output-limit') return false;
|
||||
if (!visibleAnswer || visibleAnswer.trim().length < 40) return false;
|
||||
if (!Number.isFinite(maxOutputTokens) || maxOutputTokens <= 0) return true;
|
||||
return outputTokens >= Math.floor(maxOutputTokens * 0.8);
|
||||
const v = (visibleAnswer || '').trim();
|
||||
if (v.length < 24) return false;
|
||||
// These won't be fixed by generating more text — don't auto-continue.
|
||||
if (stopKind === 'user-stopped' || stopKind === 'context-overflow' || stopKind === 'error' || stopKind === 'tool-calls') return false;
|
||||
if (stopKind === 'output-limit') return true;
|
||||
if (Number.isFinite(maxOutputTokens) && maxOutputTokens > 0 && outputTokens >= Math.floor(maxOutputTokens * 0.85)) return true;
|
||||
// 'complete' (eosFound) or 'unknown' but the text is plainly unfinished → continue.
|
||||
return looksCutOff(v);
|
||||
}
|
||||
|
||||
/** Appended to the system prompt for a final-only retry — the previous reply was reasoning-only. */
|
||||
|
||||
Reference in New Issue
Block a user