feat(gateway): 链路图冷启动快照(v0.71)+ 面板来源说明条 —— 修「轮次结束后打开页面一片空白」
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- 断点已证 = **时序层**:graph_update 只走实时帧从不重放、flowGraphs 不持久化、补拉通路此前根本不存在(EndRound 注释承诺过「刷新能重放」,代码里从来没有)
  铁证:15:16:38 页面重载抹掉 15:09 那轮图,而下一轮心跳要等 ~15:24 ⇒ 打开后台思考页时桶必然为空
- 新增只读端点 GET /api/v1/admin/flow/graph?sessionId=(owner|admin;省略=主会话;graph 与 graph_update 帧的 data 逐字同形)
  无图 ⇒ 200 + graph:null(不画假图);图源未接线 ⇒ 500 flow_unavailable(不伪装成「没有图」);不审计、不发布
- loop.FlowPublisher.LastGraph:只读快照(不发布/不改图/不动轮次计数),FlowGraph.Clone 深拷贝避免锁外编码撕裂
- 前端 useFlowSnapshot:只在「本会话还没有图」时补拉(避免每行一个请求);Flow/Agents/Backthink 三处接入 + 来源说明条(明确「最近一轮」与「多轮历史回放尚未实现」)
- 变异实测:LastGraph 恒 nil ⇒ 4 条测试红;白名单去掉 sess-backthink ⇒ 对应测试红(首次变异因未使用 import 编译失败 ⇒ 已作废重做)
- ⚠️ 诚实边界:每会话只回**最近一轮**(多轮回放属 F2);白名单外会话(IM 群聊/陌生人)永远没有图;**后端重启后未跑新轮次前端点如实返 null(图是内存资产,不落库)**—— 主人要的「本地数据」正是 F2 要补的
This commit is contained in:
AskaEth committed 2026-10-05 15:38:53 +08:00
1 parent a3482ed06e
commit 1bf85a955b
23 files changed
+1427 -36

No files matched your search

@@ -0,0 +1,49 @@
import { BACKTHINK_SESSION_ID } from "../../../store/sessionCache";
/** 会话 id → 人话标签(图上「这是哪个会话的图」必须看得懂)。未知会话
* 原样显示 id,绝不猜一个更好听的名字。 */
function sessionLabel(sessionId: string): string {
if (sessionId === BACKTHINK_SESSION_ID) return "后台思考会话";
if (sessionId === "web") return "Web 主会话";
return sessionId;
}
/** 链路图快照的诚实说明条(契约 v0.71 §4.11(b)-1)。
*
* 为什么必须有它:后端只保留**每个会话最近一轮**的图,而补拉通路的用途正是
* 「轮次结束后才打开页面」。于是图上画的到底是哪一种来源必须讲清:
* - `snapshot` = 打开页面时**只读拉取**的那一份最近一轮(不是实时帧,也**不一定
* 是你眼前这一行那一轮** —— 后台思考行尤其如此);
* - `live` = 这次页面存活期间**实时收到**的图(正在跑 / 刚跑完的那一轮)。
*
* 不写这一条就等于让用户以为「这行思考有自己的图」,那是把推导当事实:
* 多轮历史回放仍未实现(`design/19 §4` P3)。 */
export function FlowSnapshotHint({
sessionId,
source,
}: {
sessionId: string;
source: "live" | "snapshot";
}): React.ReactNode {
const label = sessionLabel(sessionId);
return (
<div className="rounded-[var(--mu-radius)] border border-dashed border-[var(--mu-glass-border)] px-3 py-2 text-xs text-[var(--mu-text-lo)]">
{source === "snapshot" ? (
<>
以上是 <span className="text-[var(--mu-text-mid)]">{label}</span>(
<code>{sessionId}</code>)的
<span className="text-[var(--mu-text-mid)]">最近一轮</span>
链路图快照 —— 打开本页时只读拉取(<code>GET /api/v1/admin/flow/graph</code>)。
它不一定是你要找的那一轮:后端每会话只保留最近一份图,多轮历史回放尚未实现(design/19 §4 P3)。
</>
) : (
<>
以上是 <span className="text-[var(--mu-text-mid)]">{label}</span>(
<code>{sessionId}</code>)在本次页面存活期间
<span className="text-[var(--mu-text-mid)]">实时收到</span>
的链路图(正在跑或最近跑完的那一轮)。刷新页面后它由「最近一轮快照」补上。
</>
)}
</div>
);
}