fix: cache session list model resolution (#77650) (thanks @ragesaq)

This commit is contained in:
Ayaan Zaidi
2026-05-05 11:51:16 +05:30
parent 7f27c42ebd
commit eab494ca6a
2 changed files with 39 additions and 3 deletions

View File

@@ -306,6 +306,7 @@ Docs: https://docs.openclaw.ai
- Security/Windows: route the `.cmd`/`.bat` process wrapper through the shared Windows install-root resolver instead of `process.env.ComSpec`, so workspace dotenv-blocked `SystemRoot`/`WINDIR` overrides and unsafe values like UNC paths or path-lists cannot redirect `cmd.exe` selection on Windows. (#77472) Thanks @drobison00.
- Agents/bootstrap: honor `BOOTSTRAP.md` content injected by `agent:bootstrap` hooks when deciding whether bootstrap is pending, so hook-provided required setup instructions are included in the system prompt. (#77501) Thanks @ificator.
- Agents/replay-history: drop trailing assistant turns whose content is empty or carries only the stream-error sentinel before sending the transcript to the provider, so prefill-strict providers (such as github-copilot/claude-opus-4.6) no longer reject the request with `400 The conversation must end with a user message` after a session whose last turn errored before producing content. Refs #77228. (#77287) Thanks @openperf.
- Gateway/sessions: cache selected model override resolution while building session-list rows so `openclaw sessions` and Control UI session lists stay responsive on model-heavy stores. (#77650) Thanks @ragesaq.
## 2026.5.3-1

View File

@@ -372,6 +372,7 @@ function shouldKeepStoreOnlyChildLink(entry: SessionEntry, now: number): boolean
type SessionListRowContext = {
subagentRuns: ReturnType<typeof buildSubagentRunReadIndex>;
storeChildSessionsByKey: Map<string, string[]>;
selectedModelByOverrideRef: Map<string, ReturnType<typeof resolveSessionModelRef>>;
thinkingLevelsByModelRef: Map<string, ReturnType<typeof listThinkingLevelOptions>>;
};
@@ -489,6 +490,7 @@ function buildSessionListRowContext(params: {
return {
subagentRuns,
storeChildSessionsByKey: buildStoreChildSessionIndex(params.store, params.now, subagentRuns),
selectedModelByOverrideRef: new Map(),
thinkingLevelsByModelRef: new Map(),
};
}
@@ -497,6 +499,36 @@ function createSessionRowModelCacheKey(provider: string | undefined, model: stri
return `${normalizeLowercaseStringOrEmpty(provider)}\0${normalizeOptionalString(model) ?? ""}`;
}
function resolveSessionSelectedModelRef(params: {
cfg: OpenClawConfig;
entry?: SessionEntry;
agentId: string;
rowContext?: SessionListRowContext;
}): ReturnType<typeof resolveSessionModelRef> | null {
const override = normalizeStoredOverrideModel({
providerOverride: params.entry?.providerOverride,
modelOverride: params.entry?.modelOverride,
});
if (!override.modelOverride) {
return null;
}
if (!params.rowContext) {
return resolveSessionModelRef(params.cfg, params.entry, params.agentId);
}
const key = [
normalizeAgentId(params.agentId),
override.providerOverride ?? "",
override.modelOverride,
].join("\0");
const cached = params.rowContext.selectedModelByOverrideRef.get(key);
if (cached) {
return cached;
}
const selected = resolveSessionModelRef(params.cfg, params.entry, params.agentId);
params.rowContext.selectedModelByOverrideRef.set(key, selected);
return selected;
}
function resolveSessionRowThinkingLevels(params: {
provider: string;
model: string;
@@ -1540,9 +1572,12 @@ export function buildGatewaySessionRow(params: {
? resolveSessionRuntimeMs(subagentRun, now)
: undefined))
: undefined;
const selectedModel = entry?.modelOverride?.trim()
? resolveSessionModelRef(cfg, entry, sessionAgentId)
: null;
const selectedModel = resolveSessionSelectedModelRef({
cfg,
entry,
agentId: sessionAgentId,
rowContext,
});
const resolvedModel = resolveSessionModelIdentityRef(
cfg,
entry,