Files
Jyotisha/frontend/src/lib/consultation-entrypoint.ts
T
Jesse_ChenandClaude Opus 5.5 6ad0bea320 feat(rectification): start from an offer card in the consultation, come back to it (BUG-1247~1251)
TASK-rectification-in-chat-step1-20261006, direct execution.

- The homepage 生时校正 pill and the text trigger (isRectificationHandoffQuestion)
  are gone. The consult agent decides (RECTIFICATION_OFFER_RULE, one
  definition) and calls offer-birth-time-rectification; the server decides
  whether a card may show (self, product on, no case in progress,
  feature_pricing price). The offer is stored with the answer and travels on
  run.completed; the card hangs under that answer.
- Opening from the card binds the offer to the case in the consultation's own
  messages (no table change); GET/POST /api/rectification/cases/[caseId]/source
  find the source and go back: one divider (time changed or not), earlier
  answers captioned 按校正前的时间, and a 按新时间重新看 button that sends only
  when clicked. Auto-return after the post-adopt check or a terminal case, only
  for work done in this view.
- Model history skips the divider and notes answers written with the old time.

Full suite 4987 / fail 24, identical to 6ec8efd5 (4973 / 24), no test name
lost; tsc 0; lint 0 errors; build keeps / Static, first-load gzip +0.20%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
2026-10-07 12:58:58 +08:00

101 lines
4.2 KiB
TypeScript

import { z } from "zod";
export const consultationEntrypointSchema = z.enum([
"daily_starlanguage",
"birth_time_rectification",
// 入口已于 2026-09-15 下线,枚举值保留用于读回历史会话
"guided_topic",
]);
export type ConsultationEntrypoint = z.infer<typeof consultationEntrypointSchema>;
export const GENERAL_NO_MINUTE_DAILY_FORTUNE_QUESTION =
"请帮我看一下今天的运势,重点告诉我适合推进什么、需要注意什么。";
type ConsultationQuestionInput = {
readonly visibleQuestion: string;
readonly entrypoint: ConsultationEntrypoint | undefined;
readonly currentDate: string;
readonly consultationMode?: "verified_chart" | "unverified_birth_time" | "declared_birth_window" | "general_no_birth_time";
};
export type ResolvedConsultationQuestion =
| { readonly kind: "plain"; readonly modelQuestion: string }
| { readonly kind: "expanded"; readonly modelQuestion: string };
function compactQuestion(question: string) {
return question.normalize("NFKC").replace(/\s+/gu, " ").trim();
}
export function isGeneralDailyFortuneQuestion(question: string): boolean {
const text = compactQuestion(question);
if (!text) return false;
if (text === GENERAL_NO_MINUTE_DAILY_FORTUNE_QUESTION) return true;
if (text === "深入看今日" || text === "从今日问起" || text === "查看今日运势") return true;
return /^(?:请帮我看一下)?今天的运势/.test(text) || /^今日运势/.test(text);
}
export function shouldLoadGeneralDailyPanchanga(input: Readonly<{
consultationMode?: ConsultationQuestionInput["consultationMode"];
entrypoint?: ConsultationEntrypoint;
visibleQuestion: string;
}>): boolean {
if (input.consultationMode !== "general_no_birth_time"
&& input.consultationMode !== "declared_birth_window") return false;
return input.entrypoint === "daily_starlanguage"
|| isGeneralDailyFortuneQuestion(input.visibleQuestion);
}
function publicDailyExpansion(currentDate: string): ResolvedConsultationQuestion {
return {
kind: "expanded",
modelQuestion: [
`请依据服务器提供的 ${currentDate} 公共 Panchanga 日历摘要,回答今天的整体趋势。`,
"重点说明适合推进什么、需要注意什么,并给出一个立即可执行的行动建议。",
"这不是个人命盘结论,不包含个人上升点、宫位、大运或本命过境叠加;不要把公共日历趋势写成确定预测。",
].join("\n"),
};
}
export function pinsConsultationDomains(entrypoint: ConsultationEntrypoint | undefined): boolean {
return entrypoint === "daily_starlanguage"
|| entrypoint === "birth_time_rectification"
|| entrypoint === "guided_topic";
}
export function resolveConsultationQuestion(
input: ConsultationQuestionInput,
): ResolvedConsultationQuestion {
if (shouldLoadGeneralDailyPanchanga(input)) {
return publicDailyExpansion(input.currentDate);
}
switch (input.entrypoint) {
case undefined:
return { kind: "plain", modelQuestion: input.visibleQuestion };
case "daily_starlanguage":
return {
kind: "expanded",
modelQuestion: [
`请结合已校验的星盘资料,深入解读 ${input.currentDate} 的今日主题。`,
"请说明今日趋势、适合推进的事、需要避开的事,以及一个可以立即执行的行动建议。",
"这是探索性日提示,不是确定预测;精确事件日期只能标为候选触发,不能包装成必然结论。",
].join("\n"),
};
case "birth_time_rectification":
return {
kind: "expanded",
modelQuestion: [
"请基于已校验的出生资料继续进行生时校正辅助。",
"先判断现有证据与候选结果,再说明最有区分度的下一步;需要补充信息时优先给用户可点击、容易回答的选项。",
"候选时间必须标为待验证,不能声称是出生记录中的确定分钟,也不能在没有新证据时循环重启相同流程。",
].join("\n"),
};
case "guided_topic":
return { kind: "plain", modelQuestion: input.visibleQuestion };
default: {
const exhaustive: never = input.entrypoint;
return exhaustive;
}
}
}