import type { ConsultationDomain } from "./consultation-domain-registry.ts"; import { consultationDomainDefinition } from "./consultation-domain-registry.ts"; import type { ConsultationEntrypoint } from "./consultation-entrypoint.ts"; import { isGeneralDailyFortuneQuestion, isRectificationHandoffQuestion, } from "./consultation-entrypoint.ts"; export type ReplyTheme = ConsultationDomain; import type { ConsultationReplyMetadata } from "./consultation-reply-metadata.ts"; const GENERIC_SESSION_TITLES = new Set([ "新对话", "深入看今日", "从今日问起", "查看今日运势", "生时校正", "再次校正", "一般占星咨询", "深入看今日主题咨询", ]); function readTitle(value: string): string | undefined { const title = value.replace(/\s+/g, " ").trim(); if (!title || /[\d\p{P}\p{S}]/u.test(title)) return undefined; if (/\p{Script=Han}/u.test(title)) { const length = Array.from(title.replace(/\s/g, "")).length; return length >= 6 && length <= 14 ? title : undefined; } const words = title.split(" ").filter(Boolean); return words.length >= 3 && words.length <= 7 && title.length <= 64 ? title : undefined; } // AYANAM_SUGGESTIONS blocks are no longer produced anywhere, but stored answers from // before the follow-up chips were removed still carry them, so they stay strippable // rather than leaking a raw HTML comment into a replayed transcript. function stripAgentReplyMetadata(value: string) { let title: string | undefined; const text = value .replace(//g, "") .replace(//g, (_, rawTitle: string) => { title = readTitle(rawTitle); return ""; }) .replace(/