Skip to content

Commit 6945988

Browse files
committed
fix(gateway): cap sessions list preview hydration
1 parent 2e0acd9 commit 6945988

3 files changed

Lines changed: 51 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Docs: https://docs.openclaw.ai
1717

1818
- Google Meet: interrupt Realtime provider output when local barge-in clears playback, so command-pair audio stops model speech instead of only restarting Chrome playback. Fixes #73850. (#73834) Thanks @shhtheonlyperson.
1919
- Gateway/config: cap oversized plugin-owned schemas in the full `config.schema` response so large installed plugin sets cannot balloon Gateway RSS or crash schema clients. Thanks @vincentkoc.
20-
- Gateway/sessions: use bounded tail reads for sessions-list transcript usage fallbacks, keeping large session stores responsive when rows request derived previews. Thanks @vincentkoc.
20+
- Gateway/sessions: use bounded tail reads for sessions-list transcript usage fallbacks and cap bulk title/last-message hydration, keeping large session stores responsive when rows request derived previews. Thanks @vincentkoc.
2121
- Gateway/chat: bound chat-history transcript reads to the requested display window so large session logs no longer OOM the Gateway when clients ask for a small history page. Thanks @vincentkoc.
2222
- Voice Call/Twilio: honor stored pre-connect TwiML before realtime webhook shortcuts and reject DTMF sequences outside conversation mode, so Meet PIN entry cannot be skipped or silently dropped. Thanks @donkeykong91 and @PfanP.
2323
- Google Meet/Voice Call: play Twilio Meet DTMF before opening the realtime media stream and carry the intro as the initial Voice Call message, so the greeting is generated after Meet admits the phone participant instead of racing a live-call TwiML update. Thanks @donkeykong91 and @PfanP.

src/gateway/session-utils.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,48 @@ describe("resolveSessionModelRef", () => {
11101110
});
11111111

11121112
describe("listSessionsFromStore selected model display", () => {
1113+
test("caps transcript title and last-message hydration for bulk list responses", () => {
1114+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-sessions-list-cap-"));
1115+
try {
1116+
const storePath = path.join(tmpDir, "sessions.json");
1117+
const store: Record<string, SessionEntry> = {};
1118+
const now = Date.now();
1119+
for (let i = 0; i < 105; i += 1) {
1120+
const sessionId = `sess-${i}`;
1121+
store[`agent:main:${sessionId}`] = {
1122+
sessionId,
1123+
updatedAt: now - i,
1124+
} as SessionEntry;
1125+
fs.writeFileSync(
1126+
path.join(tmpDir, `${sessionId}.jsonl`),
1127+
[
1128+
JSON.stringify({ type: "session", version: 1, id: sessionId }),
1129+
JSON.stringify({ message: { role: "user", content: `title ${i}` } }),
1130+
JSON.stringify({ message: { role: "assistant", content: `last ${i}` } }),
1131+
].join("\n"),
1132+
"utf-8",
1133+
);
1134+
}
1135+
1136+
const result = listSessionsFromStore({
1137+
cfg: createModelDefaultsConfig({ primary: "openai/gpt-5.4" }),
1138+
storePath,
1139+
store,
1140+
opts: { includeDerivedTitles: true, includeLastMessage: true, limit: 105 },
1141+
});
1142+
1143+
expect(result.sessions).toHaveLength(105);
1144+
expect(result.sessions[0]?.derivedTitle).toBe("title 0");
1145+
expect(result.sessions[0]?.lastMessagePreview).toBe("last 0");
1146+
expect(result.sessions[99]?.derivedTitle).toBe("title 99");
1147+
expect(result.sessions[99]?.lastMessagePreview).toBe("last 99");
1148+
expect(result.sessions[100]?.derivedTitle).toBeUndefined();
1149+
expect(result.sessions[100]?.lastMessagePreview).toBeUndefined();
1150+
} finally {
1151+
fs.rmSync(tmpDir, { recursive: true, force: true });
1152+
}
1153+
});
1154+
11131155
test("shows the selected override model even when a fallback runtime model exists", () => {
11141156
const cfg = createModelDefaultsConfig({
11151157
primary: "anthropic/claude-opus-4-6",

src/gateway/session-utils.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,6 +1629,7 @@ export function listSessionsFromStore(params: {
16291629
const { cfg, storePath, store, opts } = params;
16301630
const now = Date.now();
16311631
const sessionListTranscriptUsageMaxBytes = 64 * 1024;
1632+
const sessionListTranscriptFieldRows = 100;
16321633

16331634
const includeGlobal = opts.includeGlobal === true;
16341635
const includeUnknown = opts.includeUnknown === true;
@@ -1724,20 +1725,21 @@ export function listSessionsFromStore(params: {
17241725
entries = entries.slice(0, limit);
17251726
}
17261727

1727-
const sessions = entries.map(([key, entry]) =>
1728-
buildGatewaySessionRow({
1728+
const sessions = entries.map(([key, entry], index) => {
1729+
const includeTranscriptFields = index < sessionListTranscriptFieldRows;
1730+
return buildGatewaySessionRow({
17291731
cfg,
17301732
storePath,
17311733
store,
17321734
key,
17331735
entry,
17341736
modelCatalog: params.modelCatalog,
17351737
now,
1736-
includeDerivedTitles,
1737-
includeLastMessage,
1738+
includeDerivedTitles: includeTranscriptFields && includeDerivedTitles,
1739+
includeLastMessage: includeTranscriptFields && includeLastMessage,
17381740
transcriptUsageMaxBytes: sessionListTranscriptUsageMaxBytes,
1739-
}),
1740-
);
1741+
});
1742+
});
17411743

17421744
return {
17431745
ts: now,

0 commit comments

Comments
 (0)