






















@@ -181,6 +181,25 @@ type ThinkTaggedSplitBlock =
181181| { type: "thinking"; thinking: string }
182182| { type: "text"; text: string };
183183184+const THINKING_TAG_NAME_PATTERN = String.raw`(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking)`;
185+const THINKING_TAG_OPEN_RE = new RegExp(String.raw`<\s*${THINKING_TAG_NAME_PATTERN}\s*>`, "i");
186+const THINKING_TAG_CLOSE_RE = new RegExp(
187+String.raw`<\s*\/\s*${THINKING_TAG_NAME_PATTERN}\s*>`,
188+"i",
189+);
190+const THINKING_TAG_OPEN_GLOBAL_RE = new RegExp(
191+String.raw`<\s*${THINKING_TAG_NAME_PATTERN}\s*>`,
192+"gi",
193+);
194+const THINKING_TAG_CLOSE_GLOBAL_RE = new RegExp(
195+String.raw`<\s*\/\s*${THINKING_TAG_NAME_PATTERN}\s*>`,
196+"gi",
197+);
198+export const THINKING_TAG_SCAN_RE = new RegExp(
199+String.raw`<\s*(\/?)\s*${THINKING_TAG_NAME_PATTERN}\s*>`,
200+"gi",
201+);
202+184203export function splitThinkingTaggedText(text: string): ThinkTaggedSplitBlock[] | null {
185204const trimmedStart = text.trimStart();
186205// Avoid false positives: only treat it as structured thinking when it begins
@@ -189,16 +208,13 @@ export function splitThinkingTaggedText(text: string): ThinkTaggedSplitBlock[] |
189208if (!trimmedStart.startsWith("<")) {
190209return null;
191210}
192-const openRe = /<\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking)\s*>/i;
193-const closeRe = /<\s*\/\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking)\s*>/i;
194-if (!openRe.test(trimmedStart)) {
211+if (!THINKING_TAG_OPEN_RE.test(trimmedStart)) {
195212return null;
196213}
197-if (!closeRe.test(text)) {
214+if (!THINKING_TAG_CLOSE_RE.test(text)) {
198215return null;
199216}
200217201-const scanRe = /<\s*(\/?)\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking)\s*>/gi;
202218let inThinking = false;
203219let cursor = 0;
204220let thinkingStart = 0;
@@ -218,7 +234,7 @@ export function splitThinkingTaggedText(text: string): ThinkTaggedSplitBlock[] |
218234blocks.push({ type: "thinking", thinking: cleaned });
219235};
220236221-for (const match of text.matchAll(scanRe)) {
237+for (const match of text.matchAll(THINKING_TAG_SCAN_RE)) {
222238const index = match.index ?? 0;
223239const isClose = match[1]?.includes("/") ?? false;
224240@@ -299,11 +315,10 @@ export function extractThinkingFromTaggedText(text: string): string {
299315if (!text) {
300316return "";
301317}
302-const scanRe = /<\s*(\/?)\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking)\s*>/gi;
303318let result = "";
304319let lastIndex = 0;
305320let inThinking = false;
306-for (const match of text.matchAll(scanRe)) {
321+for (const match of text.matchAll(THINKING_TAG_SCAN_RE)) {
307322const idx = match.index ?? 0;
308323if (inThinking) {
309324result += text.slice(lastIndex, idx);
@@ -324,13 +339,11 @@ export function extractThinkingFromTaggedStream(text: string): string {
324339return closed;
325340}
326341327-const openRe = /<\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking)\s*>/gi;
328-const closeRe = /<\s*\/\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking)\s*>/gi;
329-const openMatches = [...text.matchAll(openRe)];
342+const openMatches = [...text.matchAll(THINKING_TAG_OPEN_GLOBAL_RE)];
330343if (openMatches.length === 0) {
331344return "";
332345}
333-const closeMatches = [...text.matchAll(closeRe)];
346+const closeMatches = [...text.matchAll(THINKING_TAG_CLOSE_GLOBAL_RE)];
334347const lastOpen = openMatches[openMatches.length - 1];
335348const lastClose = closeMatches[closeMatches.length - 1];
336349if (lastClose && (lastClose.index ?? -1) > (lastOpen.index ?? -1)) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。