feat(h5-session): Session Broker、run SSE replay 与 Finish 竞态修复

落地 H5 Session 架构 Patch 1–5(Broker 收口、Router decision、SSE taxonomy、goosed 边界检查),
并新增可选 MEMIND_RUN_STREAM_REPLAY run 事件回放与 H5 假交付 guard;修复 Finish 先于 agent-run
gate 导致 UI 永久 loading 的竞态,接入 verify:h5-session-patches 回归脚本。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-07-06 14:19:48 +08:00
parent e2ad3bf62b
commit 08feae8bef
41 changed files with 2728 additions and 130 deletions
+12 -2
View File
@@ -48,6 +48,10 @@ import type {
import { buildContextPrefix } from '../utils/mindspaceChatContext';
import { buildUserAddressPrefix } from '../utils/userAddress';
import { buildAutoChatSkillPrefix } from '../../chat-skills.mjs';
import {
resolvePostAgentRunChatState,
shouldPromoteSessionIdToStreaming,
} from '../../chat-agent-run-gate.mjs';
import { mergeConversationSnapshot } from '../../chat-finish-sync.mjs';
import {
CHAT_IMAGE_UPLOAD_MAX_INPUT_BYTES,
@@ -1366,7 +1370,9 @@ export function useTKMindChat(
}
if (!isDirectChatSessionId(sessionId)) {
subscribeToSession(sessionId);
setChatState('streaming');
if (shouldPromoteSessionIdToStreaming(chatStateRef.current)) {
setChatState('streaming');
}
}
},
onMessages: (snapshotMessages) => {
@@ -1443,7 +1449,11 @@ export function useTKMindChat(
// Fall through to agent streaming when the snapshot is not ready yet.
}
subscribeToSession(activeSessionId);
if (finishedViaPortalDirectChat) {
const nextChatState = resolvePostAgentRunChatState({
chatState: chatStateRef.current,
finishedViaPortalDirectChat,
});
if (nextChatState === 'idle') {
clearActiveRequestMissingTimer();
activeRequestId.current = null;
setChatState('idle');