惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
V
V2EX
爱范儿
爱范儿
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Martin Fowler
Martin Fowler
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Apple Machine Learning Research
Apple Machine Learning Research
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
宝玉的分享
宝玉的分享
Last Week in AI
Last Week in AI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
罗磊的独立博客
小众软件
小众软件
Vercel News
Vercel News
博客园 - 司徒正美
阮一峰的网络日志
阮一峰的网络日志
V
Visual Studio Blog
J
Java Code Geeks
P
Proofpoint News Feed
MongoDB | Blog
MongoDB | Blog
B
Blog
美团技术团队
量子位

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
perf: speed up tui session refresh · openclaw/openclaw@18...
steipete · 2026-05-31 · via Recent Commits to openclaw:main

@@ -445,6 +445,8 @@ type SessionListRowContext = {

445445

modelCostConfigByModelRef: Map<string, ModelCostConfig | undefined>;

446446

};

447447448+

type SessionListRowContextProvider = () => SessionListRowContext;

449+448450

type SingleRowChildSessionCandidateCacheEntry = {

449451

store: Record<string, SessionEntry>;

450452

storeVersion: number;

@@ -671,16 +673,33 @@ function buildSessionListRowContext(params: {

671673

now: number;

672674

}): SessionListRowContext {

673675

const subagentRuns = buildSubagentRunReadIndex(params.now);

674-

return {

676+

return buildSessionListRowContextFromParts({

675677

subagentRuns,

676678

storeChildSessionsByKey: 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,

677689

selectedModelByOverrideRef: new Map(),

678690

thinkingMetadataByModelRef: new Map(),

679691

displayModelIdentityByKey: new Map(),

680692

modelCostConfigByModelRef: 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+684703

function buildSingleRowStoreChildSessionsByKey(params: {

685704

store: Record<string, SessionEntry>;

686705

storePath: 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+21832233

function resolveSessionListSearchModelFields(params: {

21842234

cfg: OpenClawConfig;

21852235

key: string;

@@ -2356,9 +2406,9 @@ function filterSessionEntries(params: {

23562406

opts: SessionsListParams;

23572407

now: number;

23582408

rowContext?: SessionListRowContext;

2409+

getRowContext?: SessionListRowContextProvider;

23592410

}): SessionEntryPair[] {

23602411

const { cfg, store, opts, now } = params;

2361-

const rowContext = params.rowContext;

23622412

const includeGlobal = opts.includeGlobal === true;

23632413

const includeUnknown = opts.includeUnknown === true;

23642414

const spawnedBy = typeof opts.spawnedBy === "string" ? opts.spawnedBy : "";

@@ -2403,8 +2453,9 @@ function filterSessionEntries(params: {

24032453

if (key === "unknown" || key === "global") {

24042454

return 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);

24092460

if (latest) {

24102461

const latestControllerSessionKey =

@@ -2413,8 +2464,8 @@ function filterSessionEntries(params: {

24132464

return (

24142465

latestControllerSessionKey === spawnedBy &&

24152466

shouldKeepSubagentRunChildLink(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: {

2434248524352486

if (search) {

24362487

entries = entries.filter(([key, entry]) => {

2437-

const fields = [

2488+

const cheapFields = [

24382489

resolveSessionListSearchDisplayName(key, entry),

24392490

entry?.label,

24402491

entry?.subject,

24412492

entry?.sessionId,

24422493

key,

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: {

24672526

opts: SessionsListParams;

24682527

now: number;

24692528

rowContext?: SessionListRowContext;

2529+

getRowContext?: SessionListRowContextProvider;

24702530

defaultLimit?: number;

24712531

}): SessionEntrySelection {

24722532

const filtered = filterSessionEntries(params);

@@ -2494,6 +2554,7 @@ export function filterAndSortSessionEntries(params: {

24942554

opts: SessionsListParams;

24952555

now: number;

24962556

rowContext?: SessionListRowContext;

2557+

getRowContext?: SessionListRowContextProvider;

24972558

}): [string, SessionEntry][] {

24982559

return selectSessionEntries(params).entries;

24992560

}

@@ -2523,20 +2584,30 @@ export function listSessionsFromStore(params: {

25232584

store,

25242585

opts,

25252586

now,

2526-

rowContext:

2587+

getRowContext:

25272588

hasSpawnedByFilter || Boolean(normalizeOptionalString(opts.search))

2528-

? getRowContext()

2589+

? getRowContext

25292590

: undefined,

25302591

defaultLimit: SESSIONS_LIST_DEFAULT_LIMIT,

25312592

});

25322593

const { 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);

2533260125342602

const sessions = entries.map(([key, entry], index) => {

25352603

const includeTranscriptFields = index < sessionListTranscriptFieldRows;

25362604

const rowAgentId =

25372605

key === "global" && typeof opts.agentId === "string"

25382606

? normalizeAgentId(opts.agentId)

25392607

: undefined;

2608+

const storeChildSessionsByKey =

2609+

fullRowContext?.storeChildSessionsByKey ??

2610+

buildSingleRowStoreChildSessionsByKey({ store, storePath, key, now });

25402611

return buildGatewaySessionRow({

25412612

cfg,

25422613

storePath,

@@ -2549,8 +2620,8 @@ export function listSessionsFromStore(params: {

25492620

includeDerivedTitles: includeTranscriptFields && includeDerivedTitles,

25502621

includeLastMessage: includeTranscriptFields && includeLastMessage,

25512622

transcriptUsageMaxBytes: 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:

26072678

hasSpawnedByFilter || Boolean(normalizeOptionalString(opts.search))

2608-

? getRowContext()

2679+

? getRowContext

26092680

: undefined,

26102681

defaultLimit: SESSIONS_LIST_DEFAULT_LIMIT,

26112682

});

26122683

const { 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);

2613269126142692

const sessions: GatewaySessionRow[] = [];

26152693

for (let i = 0; i < entries.length; i++) {

@@ -2619,6 +2697,9 @@ export async function listSessionsFromStoreAsync(params: {

26192697

key === "global" && typeof opts.agentId === "string"

26202698

? normalizeAgentId(opts.agentId)

26212699

: undefined;

2700+

const storeChildSessionsByKey =

2701+

fullRowContext?.storeChildSessionsByKey ??

2702+

buildSingleRowStoreChildSessionsByKey({ store, storePath, key, now });

26222703

const row = buildGatewaySessionRow({

26232704

cfg,

26242705

storePath,

@@ -2631,8 +2712,8 @@ export async function listSessionsFromStoreAsync(params: {

26312712

includeDerivedTitles: false,

26322713

includeLastMessage: false,

26332714

transcriptUsageMaxBytes: sessionListTranscriptUsageMaxBytes,

2634-

storeChildSessionsByKey: getRowContext().storeChildSessionsByKey,

2635-

rowContext: getRowContext(),

2715+

storeChildSessionsByKey,

2716+

rowContext: sharedRowContext,

26362717

skipTranscriptUsageFallback: true,

26372718

lightweightListRow: true,

26382719

});