mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-01 12:36:50 +00:00
fix(gateway): default non-finite recent transcript limits
This commit is contained in:
@@ -461,6 +461,51 @@ describe("readSessionMessages", () => {
|
||||
expectMessageFields(out[1], { role: "assistant", content: "latest", openclaw: { seq: 4 } });
|
||||
});
|
||||
|
||||
test("returns no recent messages for non-finite maxMessages", async () => {
|
||||
const sessionId = "test-session-recent-non-finite-max-messages";
|
||||
writeTranscript(tmpDir, sessionId, [
|
||||
{ type: "session", version: 1, id: sessionId },
|
||||
{ message: { role: "user", content: "old" } },
|
||||
{ message: { role: "assistant", content: "latest" } },
|
||||
]);
|
||||
|
||||
expect(
|
||||
readRecentSessionMessages(sessionId, storePath, undefined, {
|
||||
maxMessages: Number.NaN,
|
||||
maxBytes: 1024,
|
||||
}),
|
||||
).toEqual([]);
|
||||
await expect(
|
||||
readRecentSessionMessagesAsync(sessionId, storePath, undefined, {
|
||||
maxMessages: Number.POSITIVE_INFINITY,
|
||||
maxBytes: 1024,
|
||||
}),
|
||||
).resolves.toEqual([]);
|
||||
});
|
||||
|
||||
test("uses the default recent byte cap for non-finite maxBytes", async () => {
|
||||
const sessionId = "test-session-recent-non-finite-max-bytes";
|
||||
writeTranscript(tmpDir, sessionId, [
|
||||
{ type: "session", version: 1, id: sessionId },
|
||||
{ message: { role: "user", content: "old" } },
|
||||
{ message: { role: "assistant", content: "latest" } },
|
||||
]);
|
||||
|
||||
const syncOut = readRecentSessionMessages(sessionId, storePath, undefined, {
|
||||
maxMessages: 1,
|
||||
maxBytes: Number.NaN,
|
||||
});
|
||||
const asyncOut = await readRecentSessionMessagesAsync(sessionId, storePath, undefined, {
|
||||
maxMessages: 1,
|
||||
maxBytes: Number.POSITIVE_INFINITY,
|
||||
});
|
||||
|
||||
expect(syncOut).toHaveLength(1);
|
||||
expectMessageFields(syncOut[0], { role: "assistant", content: "latest" });
|
||||
expect(asyncOut).toHaveLength(1);
|
||||
expectMessageFields(asyncOut[0], { role: "assistant", content: "latest" });
|
||||
});
|
||||
|
||||
test("bounds recent-message reads for large append-only transcripts", () => {
|
||||
const sessionId = "test-session-recent-large";
|
||||
const transcriptPath = path.join(tmpDir, `${sessionId}.jsonl`);
|
||||
|
||||
@@ -4,6 +4,10 @@ import { deriveSessionTotalTokens, hasNonzeroUsage, normalizeUsage } from "../ag
|
||||
import { jsonUtf8Bytes } from "../infra/json-utf8-bytes.js";
|
||||
import { hasInterSessionUserProvenance } from "../sessions/input-provenance.js";
|
||||
import { extractAssistantVisibleText } from "../shared/chat-message-content.js";
|
||||
import {
|
||||
resolveIntegerOption,
|
||||
resolveNonNegativeIntegerOption,
|
||||
} from "../shared/number-coercion.js";
|
||||
import { escapeRegExp } from "../shared/regexp.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import { estimateStringChars, estimateTokensFromChars } from "../utils/cjk-chars.js";
|
||||
@@ -181,13 +185,24 @@ type TailTranscriptRecord = {
|
||||
record: Record<string, unknown>;
|
||||
};
|
||||
|
||||
function normalizeRecentSessionReadOptions(opts?: Partial<ReadRecentSessionMessagesOptions>) {
|
||||
const maxMessages = resolveNonNegativeIntegerOption(opts?.maxMessages, 0);
|
||||
const maxBytes = resolveIntegerOption(opts?.maxBytes, RECENT_SESSION_MESSAGES_DEFAULT_MAX_BYTES, {
|
||||
min: 1024,
|
||||
});
|
||||
const maxLines = resolveIntegerOption(opts?.maxLines, maxMessages * 20 + 20, {
|
||||
min: maxMessages,
|
||||
});
|
||||
return { maxMessages, maxBytes, maxLines };
|
||||
}
|
||||
|
||||
export function readRecentSessionMessages(
|
||||
sessionId: string,
|
||||
storePath: string | undefined,
|
||||
sessionFile?: string,
|
||||
opts?: ReadRecentSessionMessagesOptions,
|
||||
): unknown[] {
|
||||
const maxMessages = Math.max(0, Math.floor(opts?.maxMessages ?? 0));
|
||||
const { maxMessages, maxBytes, maxLines } = normalizeRecentSessionReadOptions(opts);
|
||||
if (maxMessages === 0) {
|
||||
return [];
|
||||
}
|
||||
@@ -207,13 +222,8 @@ export function readRecentSessionMessages(
|
||||
return [];
|
||||
}
|
||||
|
||||
const maxBytes = Math.max(
|
||||
1024,
|
||||
Math.floor(opts?.maxBytes ?? RECENT_SESSION_MESSAGES_DEFAULT_MAX_BYTES),
|
||||
);
|
||||
const readLen = Math.min(stat.size, maxBytes);
|
||||
const readStart = Math.max(0, stat.size - readLen);
|
||||
const maxLines = Math.max(maxMessages, Math.floor(opts?.maxLines ?? maxMessages * 20 + 20));
|
||||
|
||||
return (
|
||||
withOpenTranscriptFd(filePath, (fd) => {
|
||||
@@ -239,14 +249,9 @@ async function readRecentTranscriptTailLinesAsync(
|
||||
stat: fs.Stats,
|
||||
opts: ReadRecentSessionMessagesOptions,
|
||||
): Promise<string[]> {
|
||||
const maxMessages = Math.max(0, Math.floor(opts.maxMessages));
|
||||
const maxBytes = Math.max(
|
||||
1024,
|
||||
Math.floor(opts.maxBytes ?? RECENT_SESSION_MESSAGES_DEFAULT_MAX_BYTES),
|
||||
);
|
||||
const { maxMessages, maxBytes, maxLines } = normalizeRecentSessionReadOptions(opts);
|
||||
const readLen = Math.min(stat.size, maxBytes);
|
||||
const readStart = Math.max(0, stat.size - readLen);
|
||||
const maxLines = Math.max(maxMessages, Math.floor(opts.maxLines ?? maxMessages * 20 + 20));
|
||||
const handle = await fs.promises.open(filePath, "r");
|
||||
try {
|
||||
const buffer = Buffer.alloc(readLen);
|
||||
@@ -655,7 +660,8 @@ export async function readRecentSessionMessagesAsync(
|
||||
sessionFile?: string,
|
||||
opts?: ReadRecentSessionMessagesOptions,
|
||||
): Promise<unknown[]> {
|
||||
const maxMessages = Math.max(0, Math.floor(opts?.maxMessages ?? 0));
|
||||
const normalized = normalizeRecentSessionReadOptions(opts);
|
||||
const { maxMessages } = normalized;
|
||||
if (maxMessages === 0) {
|
||||
return [];
|
||||
}
|
||||
@@ -675,8 +681,7 @@ export async function readRecentSessionMessagesAsync(
|
||||
return [];
|
||||
}
|
||||
const lines = await readRecentTranscriptTailLinesAsync(filePath, stat, {
|
||||
...opts,
|
||||
maxMessages,
|
||||
...normalized,
|
||||
});
|
||||
return parseRecentTranscriptTailMessages(lines, maxMessages);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user