Skip to content

Commit 0e86ca1

Browse files
committed
fix(gateway): default non-finite recent transcript limits
1 parent 22e8cd2 commit 0e86ca1

2 files changed

Lines changed: 65 additions & 15 deletions

File tree

src/gateway/session-utils.fs.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,51 @@ describe("readSessionMessages", () => {
461461
expectMessageFields(out[1], { role: "assistant", content: "latest", openclaw: { seq: 4 } });
462462
});
463463

464+
test("returns no recent messages for non-finite maxMessages", async () => {
465+
const sessionId = "test-session-recent-non-finite-max-messages";
466+
writeTranscript(tmpDir, sessionId, [
467+
{ type: "session", version: 1, id: sessionId },
468+
{ message: { role: "user", content: "old" } },
469+
{ message: { role: "assistant", content: "latest" } },
470+
]);
471+
472+
expect(
473+
readRecentSessionMessages(sessionId, storePath, undefined, {
474+
maxMessages: Number.NaN,
475+
maxBytes: 1024,
476+
}),
477+
).toEqual([]);
478+
await expect(
479+
readRecentSessionMessagesAsync(sessionId, storePath, undefined, {
480+
maxMessages: Number.POSITIVE_INFINITY,
481+
maxBytes: 1024,
482+
}),
483+
).resolves.toEqual([]);
484+
});
485+
486+
test("uses the default recent byte cap for non-finite maxBytes", async () => {
487+
const sessionId = "test-session-recent-non-finite-max-bytes";
488+
writeTranscript(tmpDir, sessionId, [
489+
{ type: "session", version: 1, id: sessionId },
490+
{ message: { role: "user", content: "old" } },
491+
{ message: { role: "assistant", content: "latest" } },
492+
]);
493+
494+
const syncOut = readRecentSessionMessages(sessionId, storePath, undefined, {
495+
maxMessages: 1,
496+
maxBytes: Number.NaN,
497+
});
498+
const asyncOut = await readRecentSessionMessagesAsync(sessionId, storePath, undefined, {
499+
maxMessages: 1,
500+
maxBytes: Number.POSITIVE_INFINITY,
501+
});
502+
503+
expect(syncOut).toHaveLength(1);
504+
expectMessageFields(syncOut[0], { role: "assistant", content: "latest" });
505+
expect(asyncOut).toHaveLength(1);
506+
expectMessageFields(asyncOut[0], { role: "assistant", content: "latest" });
507+
});
508+
464509
test("bounds recent-message reads for large append-only transcripts", () => {
465510
const sessionId = "test-session-recent-large";
466511
const transcriptPath = path.join(tmpDir, `${sessionId}.jsonl`);

src/gateway/session-utils.fs.ts

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import { deriveSessionTotalTokens, hasNonzeroUsage, normalizeUsage } from "../ag
44
import { jsonUtf8Bytes } from "../infra/json-utf8-bytes.js";
55
import { hasInterSessionUserProvenance } from "../sessions/input-provenance.js";
66
import { extractAssistantVisibleText } from "../shared/chat-message-content.js";
7+
import {
8+
resolveIntegerOption,
9+
resolveNonNegativeIntegerOption,
10+
} from "../shared/number-coercion.js";
711
import { escapeRegExp } from "../shared/regexp.js";
812
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
913
import { estimateStringChars, estimateTokensFromChars } from "../utils/cjk-chars.js";
@@ -181,13 +185,24 @@ type TailTranscriptRecord = {
181185
record: Record<string, unknown>;
182186
};
183187

188+
function normalizeRecentSessionReadOptions(opts?: Partial<ReadRecentSessionMessagesOptions>) {
189+
const maxMessages = resolveNonNegativeIntegerOption(opts?.maxMessages, 0);
190+
const maxBytes = resolveIntegerOption(opts?.maxBytes, RECENT_SESSION_MESSAGES_DEFAULT_MAX_BYTES, {
191+
min: 1024,
192+
});
193+
const maxLines = resolveIntegerOption(opts?.maxLines, maxMessages * 20 + 20, {
194+
min: maxMessages,
195+
});
196+
return { maxMessages, maxBytes, maxLines };
197+
}
198+
184199
export function readRecentSessionMessages(
185200
sessionId: string,
186201
storePath: string | undefined,
187202
sessionFile?: string,
188203
opts?: ReadRecentSessionMessagesOptions,
189204
): unknown[] {
190-
const maxMessages = Math.max(0, Math.floor(opts?.maxMessages ?? 0));
205+
const { maxMessages, maxBytes, maxLines } = normalizeRecentSessionReadOptions(opts);
191206
if (maxMessages === 0) {
192207
return [];
193208
}
@@ -207,13 +222,8 @@ export function readRecentSessionMessages(
207222
return [];
208223
}
209224

210-
const maxBytes = Math.max(
211-
1024,
212-
Math.floor(opts?.maxBytes ?? RECENT_SESSION_MESSAGES_DEFAULT_MAX_BYTES),
213-
);
214225
const readLen = Math.min(stat.size, maxBytes);
215226
const readStart = Math.max(0, stat.size - readLen);
216-
const maxLines = Math.max(maxMessages, Math.floor(opts?.maxLines ?? maxMessages * 20 + 20));
217227

218228
return (
219229
withOpenTranscriptFd(filePath, (fd) => {
@@ -239,14 +249,9 @@ async function readRecentTranscriptTailLinesAsync(
239249
stat: fs.Stats,
240250
opts: ReadRecentSessionMessagesOptions,
241251
): Promise<string[]> {
242-
const maxMessages = Math.max(0, Math.floor(opts.maxMessages));
243-
const maxBytes = Math.max(
244-
1024,
245-
Math.floor(opts.maxBytes ?? RECENT_SESSION_MESSAGES_DEFAULT_MAX_BYTES),
246-
);
252+
const { maxMessages, maxBytes, maxLines } = normalizeRecentSessionReadOptions(opts);
247253
const readLen = Math.min(stat.size, maxBytes);
248254
const readStart = Math.max(0, stat.size - readLen);
249-
const maxLines = Math.max(maxMessages, Math.floor(opts.maxLines ?? maxMessages * 20 + 20));
250255
const handle = await fs.promises.open(filePath, "r");
251256
try {
252257
const buffer = Buffer.alloc(readLen);
@@ -655,7 +660,8 @@ export async function readRecentSessionMessagesAsync(
655660
sessionFile?: string,
656661
opts?: ReadRecentSessionMessagesOptions,
657662
): Promise<unknown[]> {
658-
const maxMessages = Math.max(0, Math.floor(opts?.maxMessages ?? 0));
663+
const normalized = normalizeRecentSessionReadOptions(opts);
664+
const { maxMessages } = normalized;
659665
if (maxMessages === 0) {
660666
return [];
661667
}
@@ -675,8 +681,7 @@ export async function readRecentSessionMessagesAsync(
675681
return [];
676682
}
677683
const lines = await readRecentTranscriptTailLinesAsync(filePath, stat, {
678-
...opts,
679-
maxMessages,
684+
...normalized,
680685
});
681686
return parseRecentTranscriptTailMessages(lines, maxMessages);
682687
}

0 commit comments

Comments
 (0)