
























@@ -445,6 +445,8 @@ type SessionListRowContext = {
445445modelCostConfigByModelRef: Map<string, ModelCostConfig | undefined>;
446446};
447447448+type SessionListRowContextProvider = () => SessionListRowContext;
449+448450type SingleRowChildSessionCandidateCacheEntry = {
449451store: Record<string, SessionEntry>;
450452storeVersion: number;
@@ -671,16 +673,33 @@ function buildSessionListRowContext(params: {
671673now: number;
672674}): SessionListRowContext {
673675const subagentRuns = buildSubagentRunReadIndex(params.now);
674-return {
676+return buildSessionListRowContextFromParts({
675677 subagentRuns,
676678storeChildSessionsByKey: buildStoreChildSessionIndex(params.store, params.now, subagentRuns),
679+});
680+}
681+682+function buildSessionListRowContextFromParts(params: {
683+subagentRuns: ReturnType<typeof buildSubagentRunReadIndex>;
684+storeChildSessionsByKey: Map<string, string[]>;
685+}): SessionListRowContext {
686+return {
687+subagentRuns: params.subagentRuns,
688+storeChildSessionsByKey: params.storeChildSessionsByKey,
677689selectedModelByOverrideRef: new Map(),
678690thinkingMetadataByModelRef: new Map(),
679691displayModelIdentityByKey: new Map(),
680692modelCostConfigByModelRef: new Map(),
681693};
682694}
683695696+function buildSessionListRowMetadataContext(params: { now: number }): SessionListRowContext {
697+return buildSessionListRowContextFromParts({
698+subagentRuns: buildSubagentRunReadIndex(params.now),
699+storeChildSessionsByKey: new Map(),
700+});
701+}
702+684703function buildSingleRowStoreChildSessionsByKey(params: {
685704store: Record<string, SessionEntry>;
686705storePath: string;
@@ -2180,6 +2199,37 @@ function addSessionListSearchModelFields(
21802199}
21812200}
218222012202+function matchesSessionListSearch(fields: Array<string | undefined>, search: string): boolean {
2203+return fields.some(
2204+(field) => typeof field === "string" && normalizeLowercaseStringOrEmpty(field).includes(search),
2205+);
2206+}
2207+2208+function appendStoredSessionModelSearchFields(
2209+fields: Array<string | undefined>,
2210+entry?: SessionEntry,
2211+) {
2212+const provider = normalizeOptionalString(entry?.modelProvider);
2213+const model = normalizeOptionalString(entry?.model);
2214+fields.push(provider, model);
2215+if (provider && model) {
2216+fields.push(`${provider}/${model}`);
2217+}
2218+}
2219+2220+function shouldResolveDerivedSessionModelSearchFields(search: string): boolean {
2221+// Agent session-key searches are already covered by cheap key fields; do not
2222+// hydrate model metadata for every non-matching row on hot TUI lookups.
2223+return !search.startsWith("agent:");
2224+}
2225+2226+function resolveSessionListRowContext(params: {
2227+rowContext?: SessionListRowContext;
2228+getRowContext?: SessionListRowContextProvider;
2229+}): SessionListRowContext | undefined {
2230+return params.rowContext ?? params.getRowContext?.();
2231+}
2232+21832233function resolveSessionListSearchModelFields(params: {
21842234cfg: OpenClawConfig;
21852235key: string;
@@ -2356,9 +2406,9 @@ function filterSessionEntries(params: {
23562406opts: SessionsListParams;
23572407now: number;
23582408rowContext?: SessionListRowContext;
2409+getRowContext?: SessionListRowContextProvider;
23592410}): SessionEntryPair[] {
23602411const { cfg, store, opts, now } = params;
2361-const rowContext = params.rowContext;
23622412const includeGlobal = opts.includeGlobal === true;
23632413const includeUnknown = opts.includeUnknown === true;
23642414const spawnedBy = typeof opts.spawnedBy === "string" ? opts.spawnedBy : "";
@@ -2403,8 +2453,9 @@ function filterSessionEntries(params: {
24032453if (key === "unknown" || key === "global") {
24042454return false;
24052455}
2406-const latest = rowContext
2407- ? rowContext.subagentRuns.getDisplaySubagentRun(key)
2456+const filterRowContext = resolveSessionListRowContext(params);
2457+const latest = filterRowContext
2458+ ? filterRowContext.subagentRuns.getDisplaySubagentRun(key)
24082459 : getSessionDisplaySubagentRunByChildSessionKey(key);
24092460if (latest) {
24102461const latestControllerSessionKey =
@@ -2413,8 +2464,8 @@ function filterSessionEntries(params: {
24132464return (
24142465latestControllerSessionKey === spawnedBy &&
24152466shouldKeepSubagentRunChildLink(latest, {
2416-activeDescendants: rowContext
2417- ? rowContext.subagentRuns.countActiveDescendantRuns(key)
2467+activeDescendants: filterRowContext
2468+ ? filterRowContext.subagentRuns.countActiveDescendantRuns(key)
24182469 : countActiveDescendantRuns(key),
24192470 now,
24202471})
@@ -2434,21 +2485,29 @@ function filterSessionEntries(params: {
2434248524352486if (search) {
24362487entries = entries.filter(([key, entry]) => {
2437-const fields = [
2488+const cheapFields = [
24382489resolveSessionListSearchDisplayName(key, entry),
24392490entry?.label,
24402491entry?.subject,
24412492entry?.sessionId,
24422493key,
2443- ...resolveSessionListSearchModelFields({
2494+];
2495+appendStoredSessionModelSearchFields(cheapFields, entry);
2496+if (matchesSessionListSearch(cheapFields, search)) {
2497+return true;
2498+}
2499+if (!shouldResolveDerivedSessionModelSearchFields(search)) {
2500+return false;
2501+}
2502+const searchRowContext = resolveSessionListRowContext(params);
2503+return matchesSessionListSearch(
2504+resolveSessionListSearchModelFields({
24442505 cfg,
24452506 key,
24462507 entry,
2447- rowContext,
2508+rowContext: searchRowContext,
24482509}),
2449-];
2450-return fields.some(
2451-(f) => typeof f === "string" && normalizeLowercaseStringOrEmpty(f).includes(search),
2510+search,
24522511);
24532512});
24542513}
@@ -2467,6 +2526,7 @@ function selectSessionEntries(params: {
24672526opts: SessionsListParams;
24682527now: number;
24692528rowContext?: SessionListRowContext;
2529+getRowContext?: SessionListRowContextProvider;
24702530defaultLimit?: number;
24712531}): SessionEntrySelection {
24722532const filtered = filterSessionEntries(params);
@@ -2494,6 +2554,7 @@ export function filterAndSortSessionEntries(params: {
24942554opts: SessionsListParams;
24952555now: number;
24962556rowContext?: SessionListRowContext;
2557+getRowContext?: SessionListRowContextProvider;
24972558}): [string, SessionEntry][] {
24982559return selectSessionEntries(params).entries;
24992560}
@@ -2523,20 +2584,30 @@ export function listSessionsFromStore(params: {
25232584 store,
25242585 opts,
25252586 now,
2526-rowContext:
2587+getRowContext:
25272588hasSpawnedByFilter || Boolean(normalizeOptionalString(opts.search))
2528- ? getRowContext()
2589+ ? getRowContext
25292590 : undefined,
25302591defaultLimit: SESSIONS_LIST_DEFAULT_LIMIT,
25312592});
25322593const { entries, totalCount, limitApplied, offset, nextOffset, hasMore } = selection;
2594+const fullRowContext =
2595+rowContext || hasSpawnedByFilter || entries.length > SESSIONS_LIST_YIELD_BATCH_SIZE
2596+ ? getRowContext()
2597+ : undefined;
2598+const sharedRowContext =
2599+fullRowContext ??
2600+(entries.length > 1 ? buildSessionListRowMetadataContext({ now }) : undefined);
2533260125342602const sessions = entries.map(([key, entry], index) => {
25352603const includeTranscriptFields = index < sessionListTranscriptFieldRows;
25362604const rowAgentId =
25372605key === "global" && typeof opts.agentId === "string"
25382606 ? normalizeAgentId(opts.agentId)
25392607 : undefined;
2608+const storeChildSessionsByKey =
2609+fullRowContext?.storeChildSessionsByKey ??
2610+buildSingleRowStoreChildSessionsByKey({ store, storePath, key, now });
25402611return buildGatewaySessionRow({
25412612 cfg,
25422613 storePath,
@@ -2549,8 +2620,8 @@ export function listSessionsFromStore(params: {
25492620includeDerivedTitles: includeTranscriptFields && includeDerivedTitles,
25502621includeLastMessage: includeTranscriptFields && includeLastMessage,
25512622transcriptUsageMaxBytes: sessionListTranscriptUsageMaxBytes,
2552-storeChildSessionsByKey: getRowContext().storeChildSessionsByKey,
2553-rowContext: getRowContext(),
2623+ storeChildSessionsByKey,
2624+rowContext: sharedRowContext,
25542625});
25552626});
25562627@@ -2603,13 +2674,20 @@ export async function listSessionsFromStoreAsync(params: {
26032674 store,
26042675 opts,
26052676 now,
2606-rowContext:
2677+getRowContext:
26072678hasSpawnedByFilter || Boolean(normalizeOptionalString(opts.search))
2608- ? getRowContext()
2679+ ? getRowContext
26092680 : undefined,
26102681defaultLimit: SESSIONS_LIST_DEFAULT_LIMIT,
26112682});
26122683const { entries, totalCount, limitApplied, offset, nextOffset, hasMore } = selection;
2684+const fullRowContext =
2685+rowContext || hasSpawnedByFilter || entries.length > SESSIONS_LIST_YIELD_BATCH_SIZE
2686+ ? getRowContext()
2687+ : undefined;
2688+const sharedRowContext =
2689+fullRowContext ??
2690+(entries.length > 1 ? buildSessionListRowMetadataContext({ now }) : undefined);
2613269126142692const sessions: GatewaySessionRow[] = [];
26152693for (let i = 0; i < entries.length; i++) {
@@ -2619,6 +2697,9 @@ export async function listSessionsFromStoreAsync(params: {
26192697key === "global" && typeof opts.agentId === "string"
26202698 ? normalizeAgentId(opts.agentId)
26212699 : undefined;
2700+const storeChildSessionsByKey =
2701+fullRowContext?.storeChildSessionsByKey ??
2702+buildSingleRowStoreChildSessionsByKey({ store, storePath, key, now });
26222703const row = buildGatewaySessionRow({
26232704 cfg,
26242705 storePath,
@@ -2631,8 +2712,8 @@ export async function listSessionsFromStoreAsync(params: {
26312712includeDerivedTitles: false,
26322713includeLastMessage: false,
26332714transcriptUsageMaxBytes: sessionListTranscriptUsageMaxBytes,
2634-storeChildSessionsByKey: getRowContext().storeChildSessionsByKey,
2635-rowContext: getRowContext(),
2715+ storeChildSessionsByKey,
2716+rowContext: sharedRowContext,
26362717skipTranscriptUsageFallback: true,
26372718lightweightListRow: true,
26382719});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。