历史回读保留尚未落盘的运行时消息;过程卡不再渲染流式正文
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 5m8s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 5m38s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 4m53s
Project CI / Backend tests (pull_request) Failing after 11s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m0s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m44s
Project CI / Repository checks (pull_request) Failing after 11s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m14s
Project CI / AI game creator shell web tests (pull_request) Failing after 3m14s
Project CI / Frontend tests (pull_request) Failing after 3m29s
Project CI / Native shell tests (pull_request) Successful in 7m10s

This commit is contained in:
2026-09-15 20:39:36 +08:00
parent 52f1d7f08b
commit 7161e934e0
2 changed files with 48 additions and 12 deletions
+47 -3
View File
@@ -534,6 +534,41 @@ function claimInitialSupervisorMessageForPage(projectPath: string) {
return true;
}
/**
* "尚未落盘的运行时消息"
*
* **** messages latch user
* replace
*
* messages "运行时拥有、且回读结果里没有"
*/
function mergeLoadedConversationWithPendingRuntimeMessages(
loaded: ChatMessage[],
current: ChatMessage[],
): ChatMessage[] {
if (current.length === 0) {
return loaded;
}
const loadedIds = new Set(
loaded
.map((message) => message.messageId)
.filter((id): id is string => Boolean(id)),
);
const loadedTexts = new Set(
loaded.map((message) => `${message.role}\u0000${message.text}`),
);
const pending = current.filter((message) => {
if (!message.runtimeOwned) {
return false;
}
if (message.messageId) {
return !loadedIds.has(message.messageId);
}
return !loadedTexts.has(`${message.role}\u0000${message.text}`);
});
return pending.length > 0 ? [...loaded, ...pending] : loaded;
}
export { AuthenticatedClient } from './app/AuthenticatedClient';
export type { PendingCommand } from './app/types';
export {
@@ -3475,8 +3510,12 @@ export function App({
setProjectSupervisorResponseStream(null);
}
setConversationVisibleCount(CONVERSATION_INITIAL_VISIBLE_COUNT);
setMessages(() => {
const nextMessages = conversationMessages;
setMessages((current) => {
// 不能整体替换:乐观插入、尚未落盘的用户消息会被冲掉(初始需求看不到就是这个原因)。
const nextMessages = mergeLoadedConversationWithPendingRuntimeMessages(
conversationMessages,
current,
);
savedConversationProjectPathRef.current = nextProjectPath;
savedConversationCountRef.current = nextMessages.length;
latestMessagesRef.current = nextMessages;
@@ -3690,7 +3729,12 @@ export function App({
}
setProjectSupervisorRuntimeError(runtimeError || resumeError);
setMessages((current) => {
const nextConversationMessages = conversationMessages;
// replace 分支同样不能丢掉尚未落盘的运行时消息(初始需求)。
const nextConversationMessages =
mergeLoadedConversationWithPendingRuntimeMessages(
conversationMessages,
current,
);
const hasOnlyDefaultGreeting =
current.length === 1 &&
current[0]?.role === 'assistant' &&
@@ -591,15 +591,7 @@ export function ProjectSupervisorView({
: '陶泥儿正在处理'}
</strong>
</header>
{transientReply ? (
<div aria-label="陶泥儿实时回复">
<ChatMarkdownMessage
role="assistant"
text={transientReply}
streaming
/>
</div>
) : null}
{directProcessDetail ? (
<div className="project-supervisor-process-detail">
<p