mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 10:10:45 +00:00
fix(gateway): add lightweight row path for sessions.list to reduce event-loop blocking
sessions.list calls buildGatewaySessionRow for every visible session,
running transcript usage fallback, display model inference, cost/context
recomputation, thinking level enumeration, agent runtime metadata, and
plugin extension projection per row. On installs with 30-50+ sessions
this blocks the event loop for 20-80+ seconds, starving Discord
heartbeats and Control UI RPCs.
Add skipTranscriptUsageFallback and lightweightListRow flags to
buildGatewaySessionRow. In lightweight mode, skip transcript usage
fallback, display model inference, cost/context recomputation, thinking
level options, agent runtime metadata, and plugin extension projection.
Use persisted entry fields directly for cost, tokens, and model identity.
listSessionsFromStoreAsync now passes both flags for bulk list rows.
Detail endpoints and single-row loads are unaffected.
Observed improvement on a production install (33 sessions):
sessions.list row construction dropped from ~82s to ~6s.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit 803879ec54)
This commit is contained in:
committed by
Vincent Koc
parent
4c9a557533
commit
7fe4ba013f
@@ -1430,8 +1430,12 @@ export function buildGatewaySessionRow(params: {
|
||||
transcriptUsageMaxBytes?: number;
|
||||
storeChildSessionsByKey?: Map<string, string[]>;
|
||||
rowContext?: SessionListRowContext;
|
||||
skipTranscriptUsageFallback?: boolean;
|
||||
lightweightListRow?: boolean;
|
||||
}): GatewaySessionRow {
|
||||
const { cfg, storePath, store, key, entry } = params;
|
||||
const lightweight = params.lightweightListRow === true;
|
||||
const skipTranscriptUsage = params.skipTranscriptUsageFallback === true;
|
||||
const now = params.now ?? Date.now();
|
||||
const updatedAt = entry?.updatedAt ?? null;
|
||||
const parsed = parseGroupKey(key);
|
||||
@@ -1533,7 +1537,8 @@ export function buildGatewaySessionRow(params: {
|
||||
entry,
|
||||
}) === undefined;
|
||||
const transcriptUsage =
|
||||
needsTranscriptTotalTokens || needsTranscriptContextTokens || needsTranscriptEstimatedCostUsd
|
||||
!skipTranscriptUsage &&
|
||||
(needsTranscriptTotalTokens || needsTranscriptContextTokens || needsTranscriptEstimatedCostUsd)
|
||||
? resolveTranscriptUsageFallback({
|
||||
cfg,
|
||||
key,
|
||||
@@ -1577,36 +1582,39 @@ export function buildGatewaySessionRow(params: {
|
||||
const latestCompactionCheckpoint = buildCompactionCheckpointPreview(
|
||||
resolveLatestCompactionCheckpoint(entry),
|
||||
);
|
||||
const agentRuntime = resolveAgentRuntimeMetadata(cfg, sessionAgentId);
|
||||
const agentRuntime = lightweight ? undefined : resolveAgentRuntimeMetadata(cfg, sessionAgentId);
|
||||
const selectedOrRuntimeModelProvider = selectedModel?.provider ?? modelProvider;
|
||||
const selectedOrRuntimeModel = selectedModel?.model ?? model;
|
||||
const rowModelIdentity = resolveSessionDisplayModelIdentityRef({
|
||||
cfg,
|
||||
agentId: sessionAgentId,
|
||||
provider: selectedOrRuntimeModelProvider,
|
||||
model: selectedOrRuntimeModel,
|
||||
});
|
||||
const rowModelIdentity = lightweight
|
||||
? { provider: selectedOrRuntimeModelProvider, model: selectedOrRuntimeModel }
|
||||
: resolveSessionDisplayModelIdentityRef({
|
||||
cfg,
|
||||
agentId: sessionAgentId,
|
||||
provider: selectedOrRuntimeModelProvider,
|
||||
model: selectedOrRuntimeModel,
|
||||
});
|
||||
const rowModelProvider = rowModelIdentity.provider;
|
||||
const rowModel = rowModelIdentity.model;
|
||||
const estimatedCostUsd =
|
||||
resolveEstimatedSessionCostUsd({
|
||||
cfg,
|
||||
provider: rowModelProvider,
|
||||
model: rowModel,
|
||||
entry,
|
||||
}) ?? resolveNonNegativeNumber(transcriptUsage?.estimatedCostUsd);
|
||||
const contextTokens =
|
||||
resolvePositiveNumber(entry?.contextTokens) ??
|
||||
resolvePositiveNumber(transcriptUsage?.contextTokens) ??
|
||||
resolvePositiveNumber(
|
||||
resolveContextTokensForModel({
|
||||
const estimatedCostUsd = lightweight
|
||||
? resolveNonNegativeNumber(entry?.estimatedCostUsd)
|
||||
: resolveEstimatedSessionCostUsd({
|
||||
cfg,
|
||||
provider: rowModelProvider,
|
||||
model: rowModel,
|
||||
// Gateway/session listing is read-only; don't start async model discovery.
|
||||
allowAsyncLoad: false,
|
||||
}),
|
||||
);
|
||||
entry,
|
||||
}) ?? resolveNonNegativeNumber(transcriptUsage?.estimatedCostUsd);
|
||||
const contextTokens = lightweight
|
||||
? resolvePositiveNumber(entry?.contextTokens)
|
||||
: resolvePositiveNumber(entry?.contextTokens) ??
|
||||
resolvePositiveNumber(transcriptUsage?.contextTokens) ??
|
||||
resolvePositiveNumber(
|
||||
resolveContextTokensForModel({
|
||||
cfg,
|
||||
provider: rowModelProvider,
|
||||
model: rowModel,
|
||||
allowAsyncLoad: false,
|
||||
}),
|
||||
);
|
||||
|
||||
let derivedTitle: string | undefined;
|
||||
let lastMessagePreview: string | undefined;
|
||||
@@ -1627,14 +1635,11 @@ export function buildGatewaySessionRow(params: {
|
||||
|
||||
const thinkingProvider = rowModelProvider ?? DEFAULT_PROVIDER;
|
||||
const thinkingModel = rowModel ?? DEFAULT_MODEL;
|
||||
const thinkingLevels = listThinkingLevelOptions(
|
||||
thinkingProvider,
|
||||
thinkingModel,
|
||||
params.modelCatalog,
|
||||
);
|
||||
const pluginExtensions = entry
|
||||
? projectPluginSessionExtensionsSync({ sessionKey: key, entry })
|
||||
: [];
|
||||
const thinkingLevels = lightweight
|
||||
? []
|
||||
: listThinkingLevelOptions(thinkingProvider, thinkingModel, params.modelCatalog);
|
||||
const pluginExtensions =
|
||||
!lightweight && entry ? projectPluginSessionExtensionsSync({ sessionKey: key, entry }) : [];
|
||||
|
||||
return {
|
||||
key,
|
||||
@@ -1662,13 +1667,15 @@ export function buildGatewaySessionRow(params: {
|
||||
thinkingLevel: entry?.thinkingLevel,
|
||||
thinkingLevels,
|
||||
thinkingOptions: thinkingLevels.map((level) => level.label),
|
||||
thinkingDefault: resolveGatewaySessionThinkingDefault({
|
||||
cfg,
|
||||
provider: thinkingProvider,
|
||||
model: thinkingModel,
|
||||
agentId: sessionAgentId,
|
||||
modelCatalog: params.modelCatalog,
|
||||
}),
|
||||
thinkingDefault: lightweight
|
||||
? entry?.thinkingLevel
|
||||
: resolveGatewaySessionThinkingDefault({
|
||||
cfg,
|
||||
provider: thinkingProvider,
|
||||
model: thinkingModel,
|
||||
agentId: sessionAgentId,
|
||||
modelCatalog: params.modelCatalog,
|
||||
}),
|
||||
fastMode: entry?.fastMode,
|
||||
verboseLevel: entry?.verboseLevel,
|
||||
traceLevel: entry?.traceLevel,
|
||||
@@ -2016,6 +2023,8 @@ export async function listSessionsFromStoreAsync(params: {
|
||||
transcriptUsageMaxBytes: sessionListTranscriptUsageMaxBytes,
|
||||
storeChildSessionsByKey: getRowContext().storeChildSessionsByKey,
|
||||
rowContext: getRowContext(),
|
||||
skipTranscriptUsageFallback: true,
|
||||
lightweightListRow: true,
|
||||
});
|
||||
if (
|
||||
entry?.sessionId &&
|
||||
|
||||
Reference in New Issue
Block a user