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
+4 -1
View File
@@ -4,6 +4,7 @@ import { Readable } from 'node:stream';
import { Agent, fetch as undiciFetch } from 'undici';
import { jsonrepair } from 'jsonrepair';
import { reconcileAgentSession } from './session-reconcile.mjs';
import { resolveSessionAccess } from './session-broker.mjs';
const insecureDispatcher = new Agent({
connect: { rejectUnauthorized: false },
@@ -304,11 +305,13 @@ export function createMindSpaceAgentRunner({
apiTarget,
apiSecret,
userAuth,
sessionAccess = null,
agentJobService,
experienceService = null,
executeSessionReply = defaultExecuteSessionReply,
apiFetchImpl = null,
}) {
const sessionStore = resolveSessionAccess({ userAuth, sessionAccess });
const apiFetch = apiFetchImpl ?? (async (pathname, init = {}) => {
const url = new URL(pathname, apiTarget);
const headers = {
@@ -358,7 +361,7 @@ export function createMindSpaceAgentRunner({
if (!sessionId) {
throw runnerError('Agent 会话启动失败', 'worker_unavailable');
}
await userAuth.registerAgentSession(claim.userId, sessionId);
await sessionStore.registerAgentSession(claim.userId, sessionId);
await reconcileAgentSession(
(pathname, init) => apiFetch(pathname, init),
sessionId,