Files
Jyotisha/frontend/src/lib/think-step-gate.ts
T
jesse-ux e32ce6247e fix(consult): BUG-945~949 领域截断、思考分片、Pass 4 按模式分流
schema 上限与执行上限解耦;校正思考改分片门;日期观察不删字,保证句与无分钟个人盘退回重写。
2026-09-18 13:17:35 +08:00

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;
},
};
}