mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-11 06:14:34 +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:
@@ -133,27 +133,59 @@ function annotateInterSessionUserMessages(messages: AgentMessage[]): AgentMessag
|
||||
return touched ? out : messages;
|
||||
}
|
||||
|
||||
function stripStaleAssistantUsageBeforeLatestCompaction(messages: AgentMessage[]): AgentMessage[] {
|
||||
let latestCompactionSummaryIndex = -1;
|
||||
for (let i = 0; i < messages.length; i += 1) {
|
||||
if (messages[i]?.role === "compactionSummary") {
|
||||
latestCompactionSummaryIndex = i;
|
||||
function parseMessageTimestamp(value: unknown): number | null {
|
||||
if (typeof value === "number" && Number.isFinite(value)) {
|
||||
return value;
|
||||
}
|
||||
if (typeof value === "string") {
|
||||
const parsed = Date.parse(value);
|
||||
if (Number.isFinite(parsed)) {
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
if (latestCompactionSummaryIndex <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function stripStaleAssistantUsageBeforeLatestCompaction(messages: AgentMessage[]): AgentMessage[] {
|
||||
let latestCompactionSummaryIndex = -1;
|
||||
let latestCompactionTimestamp: number | null = null;
|
||||
for (let i = 0; i < messages.length; i += 1) {
|
||||
const entry = messages[i];
|
||||
if (entry?.role !== "compactionSummary") {
|
||||
continue;
|
||||
}
|
||||
latestCompactionSummaryIndex = i;
|
||||
latestCompactionTimestamp = parseMessageTimestamp(
|
||||
(entry as { timestamp?: unknown }).timestamp ?? null,
|
||||
);
|
||||
}
|
||||
if (latestCompactionSummaryIndex === -1) {
|
||||
return messages;
|
||||
}
|
||||
|
||||
const out = [...messages];
|
||||
let touched = false;
|
||||
for (let i = 0; i < latestCompactionSummaryIndex; i += 1) {
|
||||
const candidate = out[i] as (AgentMessage & { usage?: unknown }) | undefined;
|
||||
for (let i = 0; i < out.length; i += 1) {
|
||||
const candidate = out[i] as
|
||||
| (AgentMessage & { usage?: unknown; timestamp?: unknown })
|
||||
| undefined;
|
||||
if (!candidate || candidate.role !== "assistant") {
|
||||
continue;
|
||||
}
|
||||
if (!candidate.usage || typeof candidate.usage !== "object") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const messageTimestamp = parseMessageTimestamp(candidate.timestamp);
|
||||
const staleByTimestamp =
|
||||
latestCompactionTimestamp !== null &&
|
||||
messageTimestamp !== null &&
|
||||
messageTimestamp <= latestCompactionTimestamp;
|
||||
const staleByLegacyOrdering = i < latestCompactionSummaryIndex;
|
||||
if (!staleByTimestamp && !staleByLegacyOrdering) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const candidateRecord = candidate as unknown as Record<string, unknown>;
|
||||
const { usage: _droppedUsage, ...rest } = candidateRecord;
|
||||
out[i] = rest as unknown as AgentMessage;
|
||||
|
||||
@@ -1162,13 +1162,15 @@ export async function runEmbeddedAttempt(
|
||||
}
|
||||
}
|
||||
|
||||
const compactionOccurredThisAttempt = getCompactionCount() > 0;
|
||||
|
||||
// Append cache-TTL timestamp AFTER prompt + compaction retry completes.
|
||||
// Previously this was before the prompt, which caused a custom entry to be
|
||||
// inserted between compaction and the next prompt — breaking the
|
||||
// prepareCompaction() guard that checks the last entry type, leading to
|
||||
// double-compaction. See: https://github.com/openclaw/openclaw/issues/9282
|
||||
// Skip when timed out during compaction — session state may be inconsistent.
|
||||
if (!timedOutDuringCompaction) {
|
||||
if (!timedOutDuringCompaction && !compactionOccurredThisAttempt) {
|
||||
const shouldTrackCacheTtl =
|
||||
params.config?.agents?.defaults?.contextPruning?.mode === "cache-ttl" &&
|
||||
isCacheTtlEligibleProvider(params.provider, params.modelId);
|
||||
@@ -1200,7 +1202,7 @@ export async function runEmbeddedAttempt(
|
||||
messagesSnapshot = snapshotSelection.messagesSnapshot;
|
||||
sessionIdUsed = snapshotSelection.sessionIdUsed;
|
||||
|
||||
if (promptError && promptErrorSource === "prompt") {
|
||||
if (promptError && promptErrorSource === "prompt" && !compactionOccurredThisAttempt) {
|
||||
try {
|
||||
sessionManager.appendCustomEntry("openclaw:prompt-error", {
|
||||
timestamp: Date.now(),
|
||||
|
||||
Reference in New Issue
Block a user