
























@@ -19,6 +19,7 @@ import {
1919import {
2020inferUniqueProviderFromConfiguredModels,
2121isCliProvider,
22+normalizeProviderId,
2223normalizeStoredOverrideModel,
2324parseModelRef,
2425resolveConfiguredModelRef,
@@ -77,6 +78,7 @@ import {
7778normalizeLowercaseStringOrEmpty,
7879normalizeOptionalString,
7980normalizeOptionalLowercaseString,
81+resolvePrimaryStringValue,
8082} from "../shared/string-coerce.js";
8183import { normalizeSessionDeliveryFields } from "../utils/delivery-context.shared.js";
8284import { estimateUsageCost, resolveModelCostConfig } from "../utils/usage-format.js";
@@ -373,6 +375,7 @@ type SessionListRowContext = {
373375subagentRuns: ReturnType<typeof buildSubagentRunReadIndex>;
374376storeChildSessionsByKey: Map<string, string[]>;
375377selectedModelByOverrideRef: Map<string, ReturnType<typeof resolveSessionModelRef>>;
378+modelIdentityByEntryKey: Map<string, ReturnType<typeof resolveSessionModelIdentityRef>>;
376379thinkingLevelsByModelRef: Map<string, ReturnType<typeof listThinkingLevelOptions>>;
377380};
378381@@ -491,6 +494,7 @@ function buildSessionListRowContext(params: {
491494 subagentRuns,
492495storeChildSessionsByKey: buildStoreChildSessionIndex(params.store, params.now, subagentRuns),
493496selectedModelByOverrideRef: new Map(),
497+modelIdentityByEntryKey: new Map(),
494498thinkingLevelsByModelRef: new Map(),
495499};
496500}
@@ -499,6 +503,116 @@ function createSessionRowModelCacheKey(provider: string | undefined, model: stri
499503return `${normalizeLowercaseStringOrEmpty(provider)}\0${normalizeOptionalString(model) ?? ""}`;
500504}
501505506+function parseQualifiedModelRefForSessionList(
507+raw: string | undefined,
508+): { provider: string; model: string } | undefined {
509+const trimmed = normalizeOptionalString(raw);
510+const slash = trimmed?.indexOf("/") ?? -1;
511+if (!trimmed || slash <= 0 || slash === trimmed.length - 1) {
512+return undefined;
513+}
514+const provider = normalizeProviderId(trimmed.slice(0, slash).trim());
515+const model = normalizeOptionalString(trimmed.slice(slash + 1));
516+return model ? { provider, model } : undefined;
517+}
518+519+function createSessionDefaultModelCacheKey(cfg: OpenClawConfig, agentId?: string): string {
520+const normalizedAgentId = normalizeAgentId(agentId);
521+const primary = normalizedAgentId
522+ ? resolveAgentEffectiveModelPrimary(cfg, normalizedAgentId)
523+ : resolvePrimaryStringValue(cfg.agents?.defaults?.model);
524+return normalizeOptionalString(primary) ?? "";
525+}
526+527+function createSessionEntryModelCacheKey(params: {
528+cfg: OpenClawConfig;
529+agentId?: string;
530+entry?:
531+| SessionEntry
532+| Pick<SessionEntry, "model" | "modelProvider" | "modelOverride" | "providerOverride">;
533+fallbackModelRef?: string;
534+}) {
535+return [
536+createSessionDefaultModelCacheKey(params.cfg, params.agentId),
537+normalizeOptionalString(params.entry?.providerOverride) ?? "",
538+normalizeOptionalString(params.entry?.modelOverride) ?? "",
539+normalizeOptionalString(params.entry?.modelProvider) ?? "",
540+normalizeOptionalString(params.entry?.model) ?? "",
541+normalizeOptionalString(params.fallbackModelRef) ?? "",
542+].join("\0");
543+}
544+545+function resolveSessionDefaultModelRefForRow(
546+cfg: OpenClawConfig,
547+agentId?: string,
548+): { provider: string; model: string } {
549+if (agentId) {
550+const primary = resolveAgentEffectiveModelPrimary(cfg, agentId)?.trim();
551+const parsed = parseQualifiedModelRefForSessionList(primary);
552+if (parsed) {
553+return parsed;
554+}
555+return resolveDefaultModelForAgent({ cfg, agentId });
556+}
557+return resolveConfiguredModelRef({
558+ cfg,
559+defaultProvider: DEFAULT_PROVIDER,
560+defaultModel: DEFAULT_MODEL,
561+});
562+}
563+564+function resolveSessionRowModelIdentityRef(params: {
565+cfg: OpenClawConfig;
566+entry?:
567+| SessionEntry
568+| Pick<SessionEntry, "model" | "modelProvider" | "modelOverride" | "providerOverride">;
569+agentId: string;
570+fallbackModelRef?: string;
571+rowContext?: SessionListRowContext;
572+}): ReturnType<typeof resolveSessionModelIdentityRef> {
573+if (!params.rowContext) {
574+return resolveSessionModelIdentityRef(
575+params.cfg,
576+params.entry,
577+params.agentId,
578+params.fallbackModelRef,
579+);
580+}
581+const key = createSessionEntryModelCacheKey({
582+cfg: params.cfg,
583+agentId: params.agentId,
584+entry: params.entry,
585+fallbackModelRef: params.fallbackModelRef,
586+});
587+const cached = params.rowContext.modelIdentityByEntryKey.get(key);
588+if (cached) {
589+return cached;
590+}
591+592+const runtimeModel = normalizeOptionalString(params.entry?.model);
593+const runtimeProvider = normalizeOptionalString(params.entry?.modelProvider);
594+if (
595+!runtimeModel &&
596+!runtimeProvider &&
597+!normalizeOptionalString(params.fallbackModelRef) &&
598+!normalizeOptionalString(params.entry?.providerOverride) &&
599+!normalizeOptionalString(params.entry?.modelOverride)
600+) {
601+const resolved = resolveSessionDefaultModelRefForRow(params.cfg, params.agentId);
602+params.rowContext.modelIdentityByEntryKey.set(key, resolved);
603+return resolved;
604+}
605+606+const resolved = resolveSessionModelIdentityRef(
607+params.cfg,
608+params.entry,
609+params.agentId,
610+params.fallbackModelRef,
611+);
612+params.rowContext.modelIdentityByEntryKey.set(key, resolved);
613+return resolved;
614+}
615+502616function resolveSessionSelectedModelRef(params: {
503617cfg: OpenClawConfig;
504618entry?: SessionEntry;
@@ -1578,12 +1692,13 @@ export function buildGatewaySessionRow(params: {
15781692agentId: sessionAgentId,
15791693 rowContext,
15801694});
1581-const resolvedModel = resolveSessionModelIdentityRef(
1695+const resolvedModel = resolveSessionRowModelIdentityRef({
15821696 cfg,
15831697 entry,
1584-sessionAgentId,
1585-subagentRun?.model,
1586-);
1698+agentId: sessionAgentId,
1699+fallbackModelRef: subagentRun?.model,
1700+ rowContext,
1701+});
15871702const runtimeModelPresent =
15881703Boolean(entry?.model?.trim()) || Boolean(entry?.modelProvider?.trim());
15891704const needsTranscriptTotalTokens =
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。