fix(workbench): recover session status from durable trace

This commit is contained in:
lyon
2026-06-19 01:34:53 +08:00
parent 587396e513
commit 111b2b468a
3 changed files with 113 additions and 4 deletions
+14 -3
View File
@@ -219,7 +219,7 @@ async function handleWorkbenchSessionList(response, url, options, actor) {
const included = await readModel.getSessionByRouteId(includeRouteId);
if (included) responseSessions = [included, ...pageSessions];
}
const summaries = responseSessions.map((session) => sessionSummary(session, options)).filter(Boolean);
const summaries = (await Promise.all(responseSessions.map(async (session) => sessionSummary(session, await sessionProjectionOptions(readModel, session, options))))).filter(Boolean);
const hasMore = naturalPage.length > limit;
sendJson(response, 200, {
ok: true,
@@ -246,11 +246,12 @@ async function handleWorkbenchSessionDetail(response, options, actor, sessionId)
const readModel = createWorkbenchReadModel(options, actor);
const session = await readModel.getSessionByRouteId(sessionId);
if (!session) return sendJson(response, 404, workbenchError("workbench_session_not_found", "Workbench session is not visible to the current actor.", { sessionId }));
const projectionOptions = await sessionProjectionOptions(readModel, session, options);
sendJson(response, 200, {
ok: true,
status: "found",
contractVersion: "workbench-session-detail-v1",
session: sessionDetail(session, options),
session: sessionDetail(session, projectionOptions),
valuesRedacted: true,
secretMaterialStored: false
});
@@ -260,7 +261,8 @@ async function handleWorkbenchMessagePage(response, url, options, actor, session
const readModel = createWorkbenchReadModel(options, actor);
const session = await readModel.getSessionByRouteId(sessionId);
if (!session) return sendJson(response, 404, workbenchError("workbench_session_not_found", "Workbench session is not visible to the current actor.", { sessionId }));
const messages = sessionMessages(session, options);
const projectionOptions = await sessionProjectionOptions(readModel, session, options);
const messages = sessionMessages(session, projectionOptions);
const limit = boundedLimit(url.searchParams.get("limit"));
const offset = cursorOffset(url.searchParams.get("cursor") ?? url.searchParams.get("after"));
const page = messages.slice(offset, offset + limit);
@@ -376,6 +378,15 @@ async function visibleSessionByTrace(store, traceId, actor) {
return canActorReadSession(session, actor) ? session : null;
}
async function sessionProjectionOptions(readModel, session, options) {
const snapshot = objectValue(session?.session);
const traceId = safeTraceId(session?.lastTraceId ?? snapshot.lastTraceId ?? snapshot.currentTraceId) ?? null;
if (!traceId) return options;
const trace = await readModel.traceSnapshot(traceId);
const result = readModel.resultForTrace(traceId);
return { ...options, trace, result };
}
function sessionSummary(session, options) {
if (!session?.id) return null;
const snapshot = objectValue(session.session);