feat(teacher): stream Yuxi reasoning and answer previews

This commit is contained in:
brother7 committed 2026-09-29 18:18:56 +08:00
1 parent f443f3bc66
commit 8ccc4650a2
12 files changed
+364 -42

No files matched your search

+38
View File
@@ -224,6 +224,44 @@ export function isTeacherReplyEnvelope(raw: string): boolean {
return withinBytes(raw, MAX_TEACHER_REPLY_BYTES) && candidates(raw.trim()).length > 0;
}
/** Preview received prose only; final validation still belongs to parseTeacherReply. */
export function previewTeacherReply(raw: string): string {
if (!withinBytes(raw, MAX_TEACHER_REPLY_BYTES)) return '';
const text = raw.trimStart();
const found = candidates(text);
if (!found.length) {
// Wait for enough of an opening JSON/fence to identify the reply envelope.
if (/^\{/.test(text)) {
try { JSON.parse(text); } catch { return ''; }
}
if (/^(`{1,3}|~{1,3})([^\n]*)$/.test(text)
|| /^(?:```|~~~)(?:json|makelore-teacher(?:-reply|-discussion)?)?\s*\n\s*\{?[^:]*$/i.test(text)) return '';
return text;
}
if (found.length !== 1) return '';
const candidate = found[0];
const scanned = fields(candidate.content);
if (scanned.duplicate || scanned.proseStart === undefined) return '';
const start = scanned.proseStart;
if (candidate.content[start] !== '"') return '';
let end = start + 1;
while (end < candidate.content.length) {
const char = candidate.content[end];
if (char === '"') break;
if (char === '\\') {
const size = candidate.content[end + 1] === 'u' ? 6 : 2;
if (end + size > candidate.content.length) break;
end += size;
} else end++;
}
try {
// Incomplete escapes remain buffered, never displayed as raw protocol text.
const prose: string = JSON.parse('"' + candidate.content.slice(start + 1, end) + '"');
return [text.slice(0, candidate.start).trim(), prose.replace(/[\uD800-\uDBFF]$/, '')]
.filter(Boolean).join('\n\n');
} catch { return ''; }
}
function projectReply(envelope: Record<string, unknown>): TeacherReply {
const reply = own(envelope, 'reply') ? envelope.reply : envelope.intro;
const suggestions = own(envelope, 'quickReplies') ? envelope.quickReplies : envelope.questions;