fix(chat): keep stored rectification titles on open
Opening a saved birth-time session no longer restamps the title or updatedAt from the wall clock. Occupies BUG-699, recurrence of BUG-553.
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import type { Dispatch, MutableRefObject, SetStateAction } from "react";
|
||||
|
||||
import { resolveSessionTitle } from "@/lib/agent-reply";
|
||||
import { rectificationOpenIdentity } from "@/lib/rectification-session-open";
|
||||
import { showChatNotice as setComposerNotice } from "@/lib/chat-notice";
|
||||
import { writeSessionUrl } from "@/lib/chat-session-url";
|
||||
import type { ConsultationEntrypoint } from "@/lib/consultation-entrypoint";
|
||||
@@ -213,16 +214,20 @@ export function useRectificationSurface(params: RectificationSurfaceParams) {
|
||||
// Merge the server-created session into the local list. The browser
|
||||
// never generates a Case id; it only mirrors the returned binding.
|
||||
const existing = sessions.find((session) => session.id === opened.sessionId);
|
||||
const merged: ChatSession = {
|
||||
id: opened.sessionId,
|
||||
const openIdentity = rectificationOpenIdentity(existing, {
|
||||
title: resolveSessionTitle("生时校正", undefined, {
|
||||
entrypoint: "birth_time_rectification",
|
||||
existingTitles: sessions.map((session) => session.title),
|
||||
}),
|
||||
updatedAt: timestamp(),
|
||||
});
|
||||
const merged: ChatSession = {
|
||||
id: opened.sessionId,
|
||||
title: openIdentity.title,
|
||||
theme: "general",
|
||||
modelId: modelCatalog.defaultModelId ?? "",
|
||||
messages: [],
|
||||
updatedAt: timestamp(),
|
||||
updatedAt: openIdentity.updatedAt,
|
||||
sessionType: "birth_time_rectification",
|
||||
rectificationCaseId: opened.caseId,
|
||||
pinned: existing?.pinned ?? false,
|
||||
|
||||
@@ -57,6 +57,9 @@ export function parseAgentReply(value: string, metadata?: ConsultationReplyMetad
|
||||
export type SessionTitleOptions = {
|
||||
readonly entrypoint?: ConsultationEntrypoint | null;
|
||||
readonly theme?: ConsultationDomain;
|
||||
/** Wall clock. Only for minting a brand-new session. Re-titling an existing
|
||||
* session must pass that session's created time; the default `new Date()`
|
||||
* would stamp today's date onto old chats (BUG-699). */
|
||||
readonly at?: Date;
|
||||
readonly existingTitles?: readonly string[];
|
||||
};
|
||||
@@ -89,7 +92,7 @@ export function resolveSessionTitle(
|
||||
modelTitle?: string,
|
||||
options: SessionTitleOptions = {},
|
||||
): string {
|
||||
const at = options.at ?? new Date();
|
||||
const at = options.at ?? new Date(); // new sessions only; see SessionTitleOptions.at
|
||||
const existingTitles = options.existingTitles ?? [];
|
||||
if (modelTitle && !isGenericSessionTitle(modelTitle)) {
|
||||
return uniquifySessionTitle(clipTitle(modelTitle), existingTitles, at);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
export function rectificationOpenIdentity(
|
||||
existing: { title: string; updatedAt: number } | undefined,
|
||||
minted: { title: string; updatedAt: number },
|
||||
): { title: string; updatedAt: number } {
|
||||
if (existing) {
|
||||
return { title: existing.title, updatedAt: existing.updatedAt };
|
||||
}
|
||||
return minted;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/** Product UI dates are wall-clock in China. Repair uses this zone, never UTC. */
|
||||
export const RECTIFICATION_TITLE_TIMEZONE = "Asia/Shanghai";
|
||||
|
||||
export const RECTIFICATION_DATED_TITLE =
|
||||
/^(\d{1,2})月(\d{1,2})日\s*·\s*生时校正(?:\s+\d{2}:\d{2})?$/;
|
||||
|
||||
export function datedRectificationTitle(
|
||||
createdAt: Date,
|
||||
timeZone = RECTIFICATION_TITLE_TIMEZONE,
|
||||
): string {
|
||||
const parts = new Intl.DateTimeFormat("en-US", {
|
||||
timeZone,
|
||||
month: "numeric",
|
||||
day: "numeric",
|
||||
}).formatToParts(createdAt);
|
||||
const month = Number(parts.find((part) => part.type === "month")?.value);
|
||||
const day = Number(parts.find((part) => part.type === "day")?.value);
|
||||
if (!Number.isInteger(month) || !Number.isInteger(day)) {
|
||||
return "生时校正";
|
||||
}
|
||||
return `${month}月${day}日 · 生时校正`;
|
||||
}
|
||||
|
||||
export function repairedRectificationTitle(row: {
|
||||
title: string;
|
||||
createdAt: Date | null;
|
||||
}): string | null {
|
||||
const matched = row.title.match(RECTIFICATION_DATED_TITLE);
|
||||
if (!matched) return null;
|
||||
if (!row.createdAt || Number.isNaN(row.createdAt.getTime())) {
|
||||
return "生时校正";
|
||||
}
|
||||
const next = datedRectificationTitle(row.createdAt);
|
||||
const nextMatch = next.match(RECTIFICATION_DATED_TITLE);
|
||||
if (
|
||||
nextMatch
|
||||
&& Number(matched[1]) === Number(nextMatch[1])
|
||||
&& Number(matched[2]) === Number(nextMatch[2])
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
Reference in New Issue
Block a user