mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-13 09:10:35 +00:00
fix(agents): harden compaction and reset safety
Co-authored-by: jaden-clovervnd <91520439+jaden-clovervnd@users.noreply.github.com> Co-authored-by: Sid <201593046+Sid-Qin@users.noreply.github.com> Co-authored-by: Marcus Widing <245375637+widingmarcus-cyber@users.noreply.github.com>
This commit is contained in:
@@ -268,6 +268,110 @@ describe("sanitizeSessionHistory", () => {
|
||||
expect(assistants[1]?.usage).toBeDefined();
|
||||
});
|
||||
|
||||
it("drops stale usage when compaction summary appears before kept assistant messages", async () => {
|
||||
vi.mocked(helpers.isGoogleModelApi).mockReturnValue(false);
|
||||
|
||||
const compactionTs = Date.parse("2026-02-26T12:00:00.000Z");
|
||||
const messages = [
|
||||
{
|
||||
role: "compactionSummary",
|
||||
summary: "compressed",
|
||||
tokensBefore: 191_919,
|
||||
timestamp: new Date(compactionTs).toISOString(),
|
||||
},
|
||||
{
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "kept pre-compaction answer" }],
|
||||
stopReason: "stop",
|
||||
timestamp: compactionTs - 1_000,
|
||||
usage: {
|
||||
input: 191_919,
|
||||
output: 2_000,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
totalTokens: 193_919,
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
||||
},
|
||||
},
|
||||
] as unknown as AgentMessage[];
|
||||
|
||||
const result = await sanitizeSessionHistory({
|
||||
messages,
|
||||
modelApi: "openai-responses",
|
||||
provider: "openai",
|
||||
sessionManager: mockSessionManager,
|
||||
sessionId: TEST_SESSION_ID,
|
||||
});
|
||||
|
||||
const assistant = result.find((message) => message.role === "assistant") as
|
||||
| (AgentMessage & { usage?: unknown })
|
||||
| undefined;
|
||||
expect(assistant?.usage).toBeUndefined();
|
||||
});
|
||||
|
||||
it("keeps fresh usage after compaction timestamp in summary-first ordering", async () => {
|
||||
vi.mocked(helpers.isGoogleModelApi).mockReturnValue(false);
|
||||
|
||||
const compactionTs = Date.parse("2026-02-26T12:00:00.000Z");
|
||||
const messages = [
|
||||
{
|
||||
role: "compactionSummary",
|
||||
summary: "compressed",
|
||||
tokensBefore: 123_000,
|
||||
timestamp: new Date(compactionTs).toISOString(),
|
||||
},
|
||||
{
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "kept pre-compaction answer" }],
|
||||
stopReason: "stop",
|
||||
timestamp: compactionTs - 2_000,
|
||||
usage: {
|
||||
input: 120_000,
|
||||
output: 3_000,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
totalTokens: 123_000,
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
||||
},
|
||||
},
|
||||
{ role: "user", content: "new question", timestamp: compactionTs + 1_000 },
|
||||
{
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "fresh answer" }],
|
||||
stopReason: "stop",
|
||||
timestamp: compactionTs + 2_000,
|
||||
usage: {
|
||||
input: 1_000,
|
||||
output: 250,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
totalTokens: 1_250,
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
||||
},
|
||||
},
|
||||
] as unknown as AgentMessage[];
|
||||
|
||||
const result = await sanitizeSessionHistory({
|
||||
messages,
|
||||
modelApi: "openai-responses",
|
||||
provider: "openai",
|
||||
sessionManager: mockSessionManager,
|
||||
sessionId: TEST_SESSION_ID,
|
||||
});
|
||||
|
||||
const assistants = result.filter((message) => message.role === "assistant") as Array<
|
||||
AgentMessage & { usage?: unknown; content?: unknown }
|
||||
>;
|
||||
const keptAssistant = assistants.find((message) =>
|
||||
JSON.stringify(message.content).includes("kept pre-compaction answer"),
|
||||
);
|
||||
const freshAssistant = assistants.find((message) =>
|
||||
JSON.stringify(message.content).includes("fresh answer"),
|
||||
);
|
||||
expect(keptAssistant?.usage).toBeUndefined();
|
||||
expect(freshAssistant?.usage).toBeDefined();
|
||||
});
|
||||
|
||||
it("keeps reasoning-only assistant messages for openai-responses", async () => {
|
||||
setNonGoogleModelApi();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user