52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
/**
|
|
* Pass 2 public thinking is a complete product sentence, never a CoT fragment.
|
|
* This gate only accepts or rejects. It must not rewrite, strip, or splice.
|
|
*/
|
|
const CJK_RE = /[\u4e00-\u9fff]/;
|
|
const SENTENCE_RE = /[。!?]/;
|
|
|
|
export const THINK_STEP_TEXT_MIN = 8;
|
|
export const THINK_STEP_TEXT_MAX = 400;
|
|
|
|
export function acceptThinkStepText(text: string): string | null {
|
|
const trimmed = text.replace(/\s+/g, " ").trim();
|
|
if (trimmed.length < THINK_STEP_TEXT_MIN || trimmed.length > THINK_STEP_TEXT_MAX) return null;
|
|
if (!CJK_RE.test(trimmed)) return null;
|
|
if (!SENTENCE_RE.test(trimmed)) return null;
|
|
return trimmed;
|
|
}
|
|
|
|
const TOOLISH_FRAGMENT_RE = /(?:rectification|run-jyotish)-[a-z0-9-]+|skill_read|proposedKind|validationErrors/i;
|
|
|
|
/**
|
|
* Rectification still publishes reasoning as fragments. This gate only accepts
|
|
* or rejects a chunk. It does not rewrite, strip English, or require 8 chars.
|
|
*/
|
|
export function acceptThinkingFragment(text: string): string | null {
|
|
const trimmed = text.replace(/\s+/g, " ").trim();
|
|
if (!trimmed) return null;
|
|
if (!CJK_RE.test(trimmed)) return null;
|
|
if (TOOLISH_FRAGMENT_RE.test(trimmed)) return null;
|
|
return trimmed;
|
|
}
|
|
|
|
export function createThinkingFragmentAssembler() {
|
|
let buffer = "";
|
|
return {
|
|
push(chunk: string): string | null {
|
|
const accepted = acceptThinkingFragment(chunk);
|
|
if (!accepted) return null;
|
|
buffer += accepted;
|
|
if (!SENTENCE_RE.test(buffer)) return null;
|
|
const released = buffer;
|
|
buffer = "";
|
|
return released;
|
|
},
|
|
flush(): string | null {
|
|
const leftover = buffer;
|
|
buffer = "";
|
|
return leftover ? acceptThinkingFragment(leftover) : null;
|
|
},
|
|
};
|
|
}
|