mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:10:43 +00:00
fix: preserve unknown compaction failure detail
This commit is contained in:
@@ -43,6 +43,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
- Gateway/hooks: route non-delivered hook completion and error summaries to the target agent's main session instead of the default agent session, preserving multi-agent hook isolation. Fixes #24693; carries forward #68667. Thanks @abersonFAC and @bluesky6868.
|
||||
- Discord: own the Carbon interaction listener and hand off Discord slash/component handling asynchronously, so compaction or long session locks no longer trip `InteractionEventListener` listener timeouts. Fixes #73204. Thanks @slideshow-dingo.
|
||||
- Compaction/diagnostics: keep unknown compaction failure classifications stable while logging sanitized detail for unclassified provider errors such as missing Ollama provider adapters. Thanks @gzsiang.
|
||||
- Gateway/startup: keep value-option foreground starts on the gateway fast path and skip proxy bootstrap unless proxy env is configured, reducing normal gateway startup RSS and avoiding full CLI graph loading. Thanks @vincentkoc.
|
||||
- Heartbeat/models: show heartbeat model bleed guidance on context-overflow resets when the last runtime model matches configured `heartbeat.model`, so smaller local heartbeat models point users to `isolatedSession` or `lightContext` instead of only compaction-buffer tuning. Fixes #67314. Thanks @Knightmare6890.
|
||||
- Subagents/models: persist `sessions_spawn.model` and configured subagent models as child-session model overrides before the first turn, so spawned subagents actually run on the requested provider/model instead of reverting to the target agent default. Fixes #73180. Thanks @danielzinhu99.
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { classifyCompactionReason, resolveCompactionFailureReason } from "./compact-reasons.js";
|
||||
import {
|
||||
classifyCompactionReason,
|
||||
formatUnknownCompactionReasonDetail,
|
||||
resolveCompactionFailureReason,
|
||||
} from "./compact-reasons.js";
|
||||
|
||||
describe("resolveCompactionFailureReason", () => {
|
||||
it("replaces generic compaction cancellation with the safeguard reason", () => {
|
||||
@@ -37,4 +41,30 @@ describe("classifyCompactionReason", () => {
|
||||
),
|
||||
).toBe("guard_blocked");
|
||||
});
|
||||
|
||||
it("keeps unclassified provider errors in the stable unknown bucket", () => {
|
||||
expect(classifyCompactionReason("No API provider registered for api: ollama")).toBe("unknown");
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatUnknownCompactionReasonDetail", () => {
|
||||
it("formats unknown reasons as single-token diagnostic detail", () => {
|
||||
expect(formatUnknownCompactionReasonDetail("No API provider registered for api: ollama")).toBe(
|
||||
"No_API_provider_registered_for_api:_ollama",
|
||||
);
|
||||
});
|
||||
|
||||
it("strips terminal escapes and log separators from unknown reasons", () => {
|
||||
expect(
|
||||
formatUnknownCompactionReasonDetail("\u001b[31mNo API\u001b[0m provider = ollama\nnext"),
|
||||
).toBe("No_API_provider_ollama_next");
|
||||
});
|
||||
|
||||
it("omits empty unknown reason detail", () => {
|
||||
expect(formatUnknownCompactionReasonDetail(" \n\t ")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("limits unknown reason detail length", () => {
|
||||
expect(formatUnknownCompactionReasonDetail("x".repeat(120))).toHaveLength(100);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
|
||||
import { sanitizeForLog } from "../../terminal/ansi.js";
|
||||
|
||||
const MAX_COMPACTION_REASON_DETAIL_CHARS = 100;
|
||||
|
||||
function isGenericCompactionCancelledReason(reason: string): boolean {
|
||||
const normalized = normalizeLowercaseStringOrEmpty(reason);
|
||||
@@ -59,3 +62,15 @@ export function classifyCompactionReason(reason?: string): string {
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
export function formatUnknownCompactionReasonDetail(reason?: string): string | undefined {
|
||||
const sanitized = sanitizeForLog((reason ?? "").replace(/\s+/g, " "))
|
||||
.trim()
|
||||
.replace(/[^A-Za-z0-9._:@/+~-]+/g, "_")
|
||||
.replace(/_+/g, "_")
|
||||
.replace(/^_+|_+$/g, "");
|
||||
if (!sanitized) {
|
||||
return undefined;
|
||||
}
|
||||
return sanitized.slice(0, MAX_COMPACTION_REASON_DETAIL_CHARS);
|
||||
}
|
||||
|
||||
@@ -97,7 +97,11 @@ import {
|
||||
resolveSkillsPromptForRun,
|
||||
} from "../skills.js";
|
||||
import { resolveSystemPromptOverride } from "../system-prompt-override.js";
|
||||
import { classifyCompactionReason, resolveCompactionFailureReason } from "./compact-reasons.js";
|
||||
import {
|
||||
classifyCompactionReason,
|
||||
formatUnknownCompactionReasonDetail,
|
||||
resolveCompactionFailureReason,
|
||||
} from "./compact-reasons.js";
|
||||
import type { CompactEmbeddedPiSessionParams, CompactionMessageMetrics } from "./compact.types.js";
|
||||
import { dedupeDuplicateUserMessagesForCompaction } from "./compaction-duplicate-user-messages.js";
|
||||
import {
|
||||
@@ -351,10 +355,14 @@ export async function compactEmbeddedPiSessionDirect(
|
||||
let thinkLevel: ThinkLevel = params.thinkLevel ?? "off";
|
||||
const attemptedThinking = new Set<ThinkLevel>();
|
||||
const fail = (reason: string): EmbeddedPiCompactResult => {
|
||||
const failureReason = classifyCompactionReason(reason);
|
||||
const detail =
|
||||
failureReason === "unknown" ? formatUnknownCompactionReasonDetail(reason) : undefined;
|
||||
const detailSuffix = detail ? ` detail=${detail}` : "";
|
||||
log.warn(
|
||||
`[compaction-diag] end runId=${runId} sessionKey=${params.sessionKey ?? params.sessionId} ` +
|
||||
`diagId=${diagId} trigger=${trigger} provider=${provider}/${modelId} ` +
|
||||
`attempt=${attempt} maxAttempts=${maxAttempts} outcome=failed reason=${classifyCompactionReason(reason)} ` +
|
||||
`attempt=${attempt} maxAttempts=${maxAttempts} outcome=failed reason=${failureReason}${detailSuffix} ` +
|
||||
`durationMs=${Date.now() - startedAt}`,
|
||||
);
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user