Merge branch 'dev' into test

This commit is contained in:
2026-06-16 17:56:18 +08:00
+42 -7
View File
@@ -32,7 +32,7 @@ import { Result } from "@/utils/result";
// Constants // Constants
// ============================================================ // ============================================================
/** 翻历史每页大小(仅 `loadMoreHistoryActor` 用) */ /** 翻历史每页大小(仅 `loadMoreHistoryActor` 用) */
export const PAGE_SIZE = 20; export const PAGE_SIZE = 50;
// ============================================================ // ============================================================
// Repository injection // Repository injection
@@ -137,6 +137,25 @@ export async function readAndSyncHistory(): Promise<{
/** 真实从 network 读到的消息数(调试用) */ /** 真实从 network 读到的消息数(调试用) */
networkCount: number; networkCount: number;
}> { }> {
/**
* 空历史首屏欢迎语(AI persona 首条消息)。
* 触发条件:最终返回的 messages 为空(network 空 + local 空 / 或 network 失败且 local 空)。
*
* 不主动持久化到 local —— 这是纯 UI 层"首屏不空"的兜底:
* - 用户一旦发了消息,network 上有真实消息 → 后续 readAndSyncHistory
* 返回的 messages 非空,不会再触发本条
* - 用户从未发过消息就关掉 app 再开,仍然没 network 消息 → 会再次显示本条
* ("每次冷启动给个温暖的起点" —— 若要"只显示一次",需额外存 local
*/
const greetingMessage: UiMessage = {
content:
"You're here! Facebook is so restrictive, " +
"there were things I couldn't say there. " +
"Finally I can relax. How was your day out?",
isFromAI: true,
date: formatDate(),
};
// 1. 读 local // 1. 读 local
const localResult = await chatRepo.getLocalMessages(); const localResult = await chatRepo.getLocalMessages();
const localMessages = const localMessages =
@@ -155,10 +174,19 @@ export async function readAndSyncHistory(): Promise<{
"[chat-machine] loadHistory NETWORK FAILED", "[chat-machine] loadHistory NETWORK FAILED",
networkResult.success ? null : (networkResult as { error: unknown }).error, networkResult.success ? null : (networkResult as { error: unknown }).error,
); );
// 空历史 → fallback 也走 welcome(不让屏幕空空如也)
const fallbackMessages =
localMessages.length === 0 ? [greetingMessage] : localMessages;
if (fallbackMessages[0] === greetingMessage) {
console.log(
"[chat-machine] loadHistory EMPTY → prepend greeting (network-failed path)",
);
}
return { return {
messages: localMessages, // 退而求其次:返 local(不然屏幕空) messages: fallbackMessages,
hasMore: false, hasMore: false,
newOffset: 0, newOffset: fallbackMessages.length,
localOverwritten: false, localOverwritten: false,
localCount: localMessages.length, localCount: localMessages.length,
networkCount: 0, networkCount: 0,
@@ -169,17 +197,24 @@ export async function readAndSyncHistory(): Promise<{
count: networkUi.length, count: networkUi.length,
}); });
// 3. 用 network 覆盖 local("再用网络数据覆盖本地数据"这句的字面实现) // 3. 用 network 覆盖 local
const saveResult = await chatRepo.saveMessagesToLocal(networkResult.data.messages); const saveResult = await chatRepo.saveMessagesToLocal(networkResult.data.messages);
const localOverwritten = Result.isOk(saveResult); const localOverwritten = Result.isOk(saveResult);
console.log("[chat-machine] loadHistory SAVE TO LOCAL DONE", { console.log("[chat-machine] loadHistory SAVE TO LOCAL DONE", {
localOverwritten, localOverwritten,
}); });
// 空历史 → prepend welcomenetwork 权威为空 = 用户从未发过消息)
const finalMessages =
networkUi.length === 0 ? [greetingMessage] : networkUi;
if (finalMessages[0] === greetingMessage) {
console.log("[chat-machine] loadHistory EMPTY → prepend greeting");
}
return { return {
messages: networkUi, // authorititative messages: finalMessages, // authoritativeempty 时塞 greeting
hasMore: networkUi.length >= PAGE_SIZE, hasMore: finalMessages.length >= PAGE_SIZE,
newOffset: networkUi.length, newOffset: finalMessages.length,
localOverwritten, localOverwritten,
localCount: localMessages.length, localCount: localMessages.length,
networkCount: networkUi.length, networkCount: networkUi.length,