From 9574e2b514aae64400538fc35e7fcb85b4e399bc Mon Sep 17 00:00:00 2001 From: Lyon <88232613+pikasTech@users.noreply.github.com> Date: Sat, 20 Jun 2026 19:34:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20PJ2026-0104010803=20P3=20=E5=90=8E?= =?UTF-8?q?=E7=AB=AF=E8=AF=BB=E4=BE=A7=E6=8E=A8=E7=90=86=E6=B8=85=E9=9B=B6?= =?UTF-8?q?=20-=20session=20list=20+=20metric=20status=20=E5=8F=AA?= =?UTF-8?q?=E8=AF=BB=20projection=20(#1757)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit server-workbench-http.ts: - sessionListProjectionOptions: 当 session snapshot 已有 durable projection 字段 (projectionStatus/terminal/sealedAt) 时,直接使用 projection 字段构建 turn projection, 不再从 compactSessionTraceResult/compactSessionTraceSnapshot 多来源混合 - recordWorkbenchProjectionMetric: status 只读 projection.status,不再 fallback 到 result?.status ?? trace?.status;source 固定为 workbench_read_model - SPEC header 更新到 draft-2026-06-20-p3-read-side-zero workbench-turn-projection.ts: - SPEC header 更新到 draft-2026-06-20-p1-zero-split-durable-realtime Closes #1749 Refs #1742 --- internal/cloud/server-workbench-http.ts | 24 +++++++++++++++------ internal/cloud/workbench-turn-projection.ts | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/internal/cloud/server-workbench-http.ts b/internal/cloud/server-workbench-http.ts index eb6e2c3e..b0de1a86 100644 --- a/internal/cloud/server-workbench-http.ts +++ b/internal/cloud/server-workbench-http.ts @@ -1,5 +1,5 @@ /* - * SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-19-p0-projector-resume; draft-2026-06-20-p1-zero-split-durable-realtime; PJ2026-010403 API契约 draft-2026-06-18-r1; PJ2026-010401 Web工作台 draft-2026-06-18-r1; PJ2026-01060505 Workbench Performance draft-2026-06-17-p0 + * SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-19-p0-projector-resume; draft-2026-06-20-p1-zero-split-durable-realtime; draft-2026-06-20-p3-read-side-zero; PJ2026-010403 API契约 draft-2026-06-18-r1; PJ2026-010401 Web工作台 draft-2026-06-18-r1; PJ2026-01060505 Workbench Performance draft-2026-06-17-p0 * 职责: Workbench REST read model。只读投影 session/message/turn/trace facts,不执行 AgentRun sync、billing finalize 或 workspace repair。 */ import { createHash } from "node:crypto"; @@ -267,10 +267,10 @@ function recordWorkbenchProjectionMetric(options = {}, { result = null, trace = projectedLatestEventAt: diagnostic?.updatedAt ?? projection?.updatedAt ?? trace?.updatedAt ?? result?.updatedAt ?? null, terminalSourceAt: workbenchTerminalSourceAt(result, projection), terminalProjectedAt: diagnostic?.projectionStatus === "caught-up" ? diagnostic?.updatedAt ?? projection?.updatedAt ?? trace?.updatedAt ?? result?.updatedAt ?? null : null, - status: projection?.status ?? result?.status ?? trace?.status ?? "unknown", + status: projection?.status ?? "unknown", reason: workbenchProjectionReason(diagnostic), projectionStatus: diagnostic?.projectionStatus ?? "unknown", - source: result?.agentRun ? "agentrun_v01" : "workbench_read_model" + source: "workbench_read_model" }); } @@ -1202,9 +1202,21 @@ function sessionListProjectionOptions(readModel, session, options) { const traceId = safeTraceId(session?.lastTraceId ?? snapshot.lastTraceId ?? snapshot.currentTraceId ?? snapshot.traceId) ?? null; if (!traceId) return options; const memoryResult = readModel.resultForTrace(traceId); - const result = memoryResult ?? compactSessionTraceResult(snapshot, session, traceId); - const memoryTrace = traceSnapshotSync(options, traceId); - const trace = compactSessionTraceSnapshot(snapshot, session, traceId, result, memoryTrace); + const hasDurableProjection = Boolean(snapshot.projectionStatus || snapshot.terminal !== undefined || snapshot.sealedAt); + const result = hasDurableProjection ? null : (memoryResult ?? compactSessionTraceResult(snapshot, session, traceId)); + const memoryTrace = hasDurableProjection ? null : traceSnapshotSync(options, traceId); + const trace = hasDurableProjection ? null : compactSessionTraceSnapshot(snapshot, session, traceId, result, memoryTrace); + if (hasDurableProjection) { + const projection = createWorkbenchTurnProjection({ + traceId, + turnId: traceId, + result: { status: snapshot.projectionStatus ?? snapshot.status, terminal: snapshot.terminal, timing: snapshot.timing, finalResponse: snapshot.finalResponse, valuesRedacted: true }, + session: null, + trace: null + }); + const projectionDiagnostic = readModel.projectionDiagnostics({ traceId, result: null, trace: null, projection }); + return { ...options, trace: null, result: null, projection, projectionDiagnostic }; + } const projection = createWorkbenchTurnProjection({ traceId, result, session, trace }); const projectionDiagnostic = readModel.projectionDiagnostics({ traceId, result, trace, projection }); return { ...options, trace, result, projection, projectionDiagnostic }; diff --git a/internal/cloud/workbench-turn-projection.ts b/internal/cloud/workbench-turn-projection.ts index 383f8bfe..4abc1f21 100644 --- a/internal/cloud/workbench-turn-projection.ts +++ b/internal/cloud/workbench-turn-projection.ts @@ -1,5 +1,5 @@ /* - * SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-19-p0-projector-resume; PJ2026-010403 API契约 draft-2026-06-18-r1. + * SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-19-p0-projector-resume; draft-2026-06-20-p1-zero-split-durable-realtime; PJ2026-010403 API契约 draft-2026-06-18-r1. * 职责: 生成唯一 Workbench turn projection;trace event 状态只作为输入证据,不直接成为 turn lifecycle。 */