perf: reduce Workbench session rail refresh cost
Pipelines as Code CI / hwlab-nc01-v03-ci-poll- Success

This commit is contained in:
root
2026-07-20 13:07:50 +02:00
parent 92d9053bea
commit 7098ef34f7
3 changed files with 62 additions and 37 deletions
@@ -43,8 +43,7 @@ export function reduceWorkbenchLiveKafkaMessageState(previous: WorkbenchLiveMess
if (previous.terminal) return previous;
const terminal = workbenchLiveKafkaEventIsTerminal(event);
const status = terminal ? firstNonEmptyString(event.status, "completed") ?? "completed" : "running";
const lifecycleEvents = [...previousEvents, event];
const assistantText = traceAssistantLifecycleEventIsSuperseded(event, lifecycleEvents, lifecycleEvents.length - 1)
const assistantText = traceAssistantLifecycleEventIsSuperseded(event, previousEvents, previousEvents.length)
? null
: workbenchLiveKafkaAssistantText(event);
return {
@@ -134,24 +134,23 @@ function reduceSessionDetail(state: WorkbenchServerState, session: WorkbenchSess
function reduceSessionList(state: WorkbenchServerState, sessions: WorkbenchSessionRecord[]): WorkbenchServerState {
const sessionIds = sessions.map((session) => session.sessionId).filter((sessionId): sessionId is string => Boolean(sessionId));
const next = sessions.reduce((current, session) => reduceSessionListItem(current, session), state);
return { ...next, sessionOrder: unique(sessionIds) };
}
function reduceSessionListItem(state: WorkbenchServerState, session: WorkbenchSessionRecord): WorkbenchServerState {
const sessionsById = { ...state.sessionsById };
const sessionStatusById = { ...state.sessionStatusById };
for (const session of sessions) {
const sessionId = session.sessionId;
if (!sessionId) return state;
const existing = state.sessionsById[sessionId];
if (!sessionId) continue;
const existing = sessionsById[sessionId];
const existingMessages = state.messagesBySessionId[sessionId] ?? existing?.messages;
const messages = Array.isArray(existingMessages) ? existingMessages : Array.isArray(session.messages) ? session.messages : [];
const merged = mergeSessionRecord(existing, { ...session, messages });
sessionsById[sessionId] = mergeSessionRecord(existing, { ...session, messages });
const sessionStatus = sessionStatusAuthorityFromDetail(session);
if (sessionStatus) sessionStatusById[sessionId] = mergeSessionStatusAuthority(sessionStatusById[sessionId], sessionStatus);
}
return {
...state,
sessionsById: { ...state.sessionsById, [sessionId]: merged },
sessionStatusById: sessionStatus
? { ...state.sessionStatusById, [sessionId]: mergeSessionStatusAuthority(state.sessionStatusById[sessionId], sessionStatus) }
: state.sessionStatusById
sessionOrder: unique(sessionIds),
sessionsById,
sessionStatusById
};
}
@@ -146,13 +146,14 @@ export function shouldShowSessionDetailLoading(input: {
export function sessionToSessionTab(session: WorkbenchSessionRecord, activeSessionId: string | null, sessionStatusAuthority: SessionStatusAuthorityMap = {}): SessionTab {
const sessionId = session.sessionId;
const updatedAt = sessionDisplayUpdatedAt(session);
const latestAgent = latestAgentMessage(session.messages);
const messageProjection = projectSessionTabMessages(session.messages);
const updatedAt = sessionDisplayUpdatedAtWithUserMessage(session, messageProjection.latestUserMessageAt);
const latestAgent = messageProjection.latestAgent;
const status = resolveSessionTabStatus(session, sessionStatusAuthority[sessionId], latestAgent);
const projection = projectionFromSession(session, sessionStatusAuthority[sessionId]);
const projectionText = projectionDiagnosticText(projection);
const trace = firstNonEmptyString(latestAgent?.traceId, latestAgent?.runnerTrace?.traceId, session.messages?.at(-1)?.traceId, session.lastTraceId);
const userMessage = session.messages?.find((message) => message.role === "user");
const trace = firstNonEmptyString(latestAgent?.traceId, latestAgent?.runnerTrace?.traceId, messageProjection.lastMessageTraceId, session.lastTraceId);
const userMessage = messageProjection.firstUser;
const running = isRunningIndicatorStatus(status);
const preview = firstReadableSentence(
session.firstUserMessagePreview,
@@ -316,7 +317,11 @@ function mergeSelectedSessionDetail(stable: WorkbenchSessionRecord[], selected:
}
function latestAgentMessage(messages: ChatMessage[] | undefined): ChatMessage | null {
return [...(messages ?? [])].reverse().find((message) => message.role === "agent") ?? null;
for (let index = (messages?.length ?? 0) - 1; index >= 0; index -= 1) {
const message = messages?.[index];
if (message?.role === "agent") return message;
}
return null;
}
function latestMessageForTrace(messages: ChatMessage[], traceId: string): ChatMessage | null {
@@ -443,8 +448,12 @@ function firstReadableSentence(...values: unknown[]): string | null {
}
export function sessionDisplayUpdatedAt(session: WorkbenchSessionRecord): string | null {
return sessionDisplayUpdatedAtWithUserMessage(session, latestUserMessageAtFromMessages(session.messages));
}
function sessionDisplayUpdatedAtWithUserMessage(session: WorkbenchSessionRecord, latestUserMessageAt: string | null): string | null {
return firstNonEmptyString(
latestUserMessageAtFromMessages(session.messages ?? []),
latestUserMessageAt,
session.lastUserMessageAt,
session.snapshot?.lastUserMessageAt,
session.startedAt,
@@ -454,22 +463,40 @@ export function sessionDisplayUpdatedAt(session: WorkbenchSessionRecord): string
}
export function latestUserMessageAtFromMessages(messages: ChatMessage[] | undefined): string | null {
const userMessageTimes = (messages ?? [])
.filter((message) => message.role === "user")
.map((message) => firstNonEmptyString(message.createdAt, message.updatedAt));
return latestTimestamp(...userMessageTimes);
let latest: { value: string; ms: number } | null = null;
let fallback: string | null = null;
for (const message of messages ?? []) {
if (message.role !== "user") continue;
const value = firstNonEmptyString(message.createdAt, message.updatedAt);
fallback ??= value;
if (!value) continue;
const ms = timestampMs(value);
if (ms && (!latest || ms > latest.ms)) latest = { value, ms };
}
return latest?.value ?? fallback;
}
function latestTimestamp(...values: unknown[]): string | null {
let latest: { value: string; ms: number } | null = null;
for (const value of values) {
const text = firstNonEmptyString(value);
if (!text) continue;
const ms = timestampMs(text);
if (!ms) continue;
if (!latest || ms > latest.ms) latest = { value: text, ms };
function projectSessionTabMessages(messages: ChatMessage[] | undefined): { latestAgent: ChatMessage | null; firstUser: ChatMessage | null; latestUserMessageAt: string | null; lastMessageTraceId: string | null } {
let latestAgent: ChatMessage | null = null;
let firstUser: ChatMessage | null = null;
let latestUserMessageAt: { value: string; ms: number } | null = null;
let firstUserMessageAt: string | null = null;
for (const message of messages ?? []) {
if (message.role === "agent") latestAgent = message;
if (message.role !== "user") continue;
firstUser ??= message;
const value = firstNonEmptyString(message.createdAt, message.updatedAt);
firstUserMessageAt ??= value;
if (!value) continue;
const ms = timestampMs(value);
if (ms && (!latestUserMessageAt || ms > latestUserMessageAt.ms)) latestUserMessageAt = { value, ms };
}
return latest?.value ?? firstNonEmptyString(...values) ?? null;
return {
latestAgent,
firstUser,
latestUserMessageAt: latestUserMessageAt?.value ?? firstUserMessageAt,
lastMessageTraceId: firstNonEmptyString(messages?.at(-1)?.traceId)
};
}
function readableSentence(value: unknown): string | null {