Skip to content

Commit fff1934

Browse files
authored
fix(gateway): build row metadata for single session lists
Refs #92057. Build the request-scoped row metadata context for every non-empty sessions.list result, including limit=1, so single-row lists use the shared subagent metadata read index instead of direct per-row registry snapshot lookups. This keeps the existing single-row store child-session candidate optimization intact while removing the single-row metadata-cache gap. Verification: - node scripts/run-vitest.mjs src/gateway/session-utils.single-row-cache.test.ts --maxWorkers=1 - .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main - Crabbox run_f89b56ffea83 / cbx_f1b1f5013225: OPENCLAW_CHECK_CHANGED_REMOTE_CHILD=1 OPENCLAW_CHANGED_LANES_RAW_SYNC=1 corepack pnpm check:changed - GitHub PR checks clean on 1ba6619
1 parent c78f937 commit fff1934

2 files changed

Lines changed: 63 additions & 3 deletions

File tree

src/gateway/session-utils.single-row-cache.test.ts

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,11 @@ const subagentRegistryReadMock = vi.hoisted(() => {
7272

7373
vi.mock("../agents/subagent-registry-read.js", () => subagentRegistryReadMock);
7474

75-
import { loadGatewaySessionRow } from "./session-utils.js";
75+
import {
76+
listSessionsFromStore,
77+
listSessionsFromStoreAsync,
78+
loadGatewaySessionRow,
79+
} from "./session-utils.js";
7680

7781
const MAIN_AGENT_ID = "main";
7882
const TEST_MODEL = "openai/gpt-5.4";
@@ -238,6 +242,62 @@ describe("single gateway session row child-session cache", () => {
238242
);
239243
});
240244

245+
test("builds shared subagent metadata context for single-row session lists", async () => {
246+
await withSingleRowCacheStore(
247+
"openclaw-single-row-list-context-",
248+
"/tmp/openclaw-single-row-list-context",
249+
async ({ now, storePath }) => {
250+
const store: Record<string, SessionEntry> = {
251+
"agent:main:discord:channel:parent": parentSession("parent", now),
252+
};
253+
const cfg: OpenClawConfig = {
254+
agents: {
255+
list: [
256+
{
257+
id: MAIN_AGENT_ID,
258+
default: true,
259+
workspace: "/tmp/openclaw-single-row-list-context",
260+
},
261+
],
262+
defaults: { model: { primary: TEST_MODEL } },
263+
},
264+
} as OpenClawConfig;
265+
266+
const syncListed = listSessionsFromStore({
267+
cfg,
268+
storePath,
269+
store,
270+
opts: { agentId: MAIN_AGENT_ID, limit: 1 },
271+
});
272+
273+
expect(syncListed.sessions).toHaveLength(1);
274+
expect(subagentRegistryReadMock.buildSubagentRunReadIndex).toHaveBeenCalledTimes(
275+
1,
276+
);
277+
expect(
278+
subagentRegistryReadMock.getSessionDisplaySubagentRunByChildSessionKey,
279+
).not.toHaveBeenCalled();
280+
281+
vi.clearAllMocks();
282+
283+
const asyncListed = await listSessionsFromStoreAsync({
284+
cfg,
285+
storePath,
286+
store,
287+
opts: { agentId: MAIN_AGENT_ID, limit: 1 },
288+
});
289+
290+
expect(asyncListed.sessions).toHaveLength(1);
291+
expect(subagentRegistryReadMock.buildSubagentRunReadIndex).toHaveBeenCalledTimes(
292+
1,
293+
);
294+
expect(
295+
subagentRegistryReadMock.getSessionDisplaySubagentRunByChildSessionKey,
296+
).not.toHaveBeenCalled();
297+
},
298+
);
299+
});
300+
241301
test("rebuilds store child candidates after same-object session store writes", async () => {
242302
await withSingleRowCacheStore(
243303
"openclaw-single-row-cache-write-version-",

src/gateway/session-utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2747,7 +2747,7 @@ export function listSessionsFromStore(params: {
27472747
: undefined;
27482748
const sharedRowContext =
27492749
fullRowContext ??
2750-
(entries.length > 1 ? buildSessionListRowMetadataContext({ now }) : undefined);
2750+
(entries.length > 0 ? buildSessionListRowMetadataContext({ now }) : undefined);
27512751

27522752
const sessions = entries.map(([key, entry], index) => {
27532753
const includeTranscriptFields = index < sessionListTranscriptFieldRows;
@@ -2837,7 +2837,7 @@ export async function listSessionsFromStoreAsync(params: {
28372837
: undefined;
28382838
const sharedRowContext =
28392839
fullRowContext ??
2840-
(entries.length > 1 ? buildSessionListRowMetadataContext({ now }) : undefined);
2840+
(entries.length > 0 ? buildSessionListRowMetadataContext({ now }) : undefined);
28412841

28422842
const sessions: GatewaySessionRow[] = [];
28432843
for (let i = 0; i < entries.length; i++) {

0 commit comments

Comments
 (0)