Skip to content

Commit be473ef

Browse files
committed
fix: keep safeguard quality guard opt-in (openclaw#25556) thanks @rodrigouroz
1 parent 566a795 commit be473ef

File tree

9 files changed

+73
-4
lines changed

9 files changed

+73
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ Docs: https://docs.openclaw.ai
165165
- Plugin runtime/system: expose `runtime.system.requestHeartbeatNow(...)` so extensions can wake targeted sessions immediately after enqueueing system events. (#19464) Thanks @AustinEral.
166166
- Plugin runtime/events: expose `runtime.events.onAgentEvent` and `runtime.events.onSessionTranscriptUpdate` for extension-side subscriptions, and isolate transcript-listener failures so one faulty listener cannot break the entire update fanout. (#16044) Thanks @scifantastic.
167167
- CLI/Banner taglines: add `cli.banner.taglineMode` (`random` | `default` | `off`) to control funny tagline behavior in startup output, with docs + FAQ guidance and regression tests for config override behavior.
168+
- Agents/compaction safeguard quality-audit rollout: keep summary quality audits disabled by default unless `agents.defaults.compaction.qualityGuard` is explicitly enabled, and add config plumbing for bounded retry control. (#25556) thanks @rodrigouroz.
168169

169170
### Breaking
170171

src/agents/pi-embedded-runner/extensions.test.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import compactionSafeguardExtension from "../pi-extensions/compaction-safeguard.
77
import { buildEmbeddedExtensionFactories } from "./extensions.js";
88

99
describe("buildEmbeddedExtensionFactories", () => {
10-
it("wires safeguard quality-guard runtime flags", () => {
10+
it("does not opt safeguard mode into quality-guard retries", () => {
1111
const sessionManager = {} as SessionManager;
1212
const model = {
1313
id: "claude-sonnet-4-20250514",
@@ -31,10 +31,44 @@ describe("buildEmbeddedExtensionFactories", () => {
3131
model,
3232
});
3333

34+
expect(factories).toContain(compactionSafeguardExtension);
35+
expect(getCompactionSafeguardRuntime(sessionManager)).toMatchObject({
36+
qualityGuardEnabled: false,
37+
});
38+
});
39+
40+
it("wires explicit safeguard quality-guard runtime flags", () => {
41+
const sessionManager = {} as SessionManager;
42+
const model = {
43+
id: "claude-sonnet-4-20250514",
44+
contextWindow: 200_000,
45+
} as Model<Api>;
46+
const cfg = {
47+
agents: {
48+
defaults: {
49+
compaction: {
50+
mode: "safeguard",
51+
qualityGuard: {
52+
enabled: true,
53+
maxRetries: 2,
54+
},
55+
},
56+
},
57+
},
58+
} as OpenClawConfig;
59+
60+
const factories = buildEmbeddedExtensionFactories({
61+
cfg,
62+
sessionManager,
63+
provider: "anthropic",
64+
modelId: "claude-sonnet-4-20250514",
65+
model,
66+
});
67+
3468
expect(factories).toContain(compactionSafeguardExtension);
3569
expect(getCompactionSafeguardRuntime(sessionManager)).toMatchObject({
3670
qualityGuardEnabled: true,
37-
qualityGuardMaxRetries: 1,
71+
qualityGuardMaxRetries: 2,
3872
});
3973
});
4074
});

src/agents/pi-embedded-runner/extensions.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export function buildEmbeddedExtensionFactories(params: {
7171
const factories: ExtensionFactory[] = [];
7272
if (resolveCompactionMode(params.cfg) === "safeguard") {
7373
const compactionCfg = params.cfg?.agents?.defaults?.compaction;
74+
const qualityGuardCfg = compactionCfg?.qualityGuard;
7475
const contextWindowInfo = resolveContextWindowInfo({
7576
cfg: params.cfg,
7677
provider: params.provider,
@@ -83,8 +84,8 @@ export function buildEmbeddedExtensionFactories(params: {
8384
contextWindowTokens: contextWindowInfo.tokens,
8485
identifierPolicy: compactionCfg?.identifierPolicy,
8586
identifierInstructions: compactionCfg?.identifierInstructions,
86-
qualityGuardEnabled: true,
87-
qualityGuardMaxRetries: 1,
87+
qualityGuardEnabled: qualityGuardCfg?.enabled ?? false,
88+
qualityGuardMaxRetries: qualityGuardCfg?.maxRetries,
8889
model: params.model,
8990
});
9091
factories.push(compactionSafeguardExtension);

src/config/config.compaction-settings.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ describe("config compaction settings", () => {
1313
reserveTokensFloor: 12_345,
1414
identifierPolicy: "custom",
1515
identifierInstructions: "Keep ticket IDs unchanged.",
16+
qualityGuard: {
17+
enabled: true,
18+
maxRetries: 2,
19+
},
1620
memoryFlush: {
1721
enabled: false,
1822
softThresholdTokens: 1234,
@@ -34,6 +38,8 @@ describe("config compaction settings", () => {
3438
expect(cfg.agents?.defaults?.compaction?.identifierInstructions).toBe(
3539
"Keep ticket IDs unchanged.",
3640
);
41+
expect(cfg.agents?.defaults?.compaction?.qualityGuard?.enabled).toBe(true);
42+
expect(cfg.agents?.defaults?.compaction?.qualityGuard?.maxRetries).toBe(2);
3743
expect(cfg.agents?.defaults?.compaction?.memoryFlush?.enabled).toBe(false);
3844
expect(cfg.agents?.defaults?.compaction?.memoryFlush?.softThresholdTokens).toBe(1234);
3945
expect(cfg.agents?.defaults?.compaction?.memoryFlush?.prompt).toBe("Write notes.");

src/config/schema.help.quality.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,9 @@ const TARGET_KEYS = [
370370
"agents.defaults.compaction.maxHistoryShare",
371371
"agents.defaults.compaction.identifierPolicy",
372372
"agents.defaults.compaction.identifierInstructions",
373+
"agents.defaults.compaction.qualityGuard",
374+
"agents.defaults.compaction.qualityGuard.enabled",
375+
"agents.defaults.compaction.qualityGuard.maxRetries",
373376
"agents.defaults.compaction.memoryFlush",
374377
"agents.defaults.compaction.memoryFlush.enabled",
375378
"agents.defaults.compaction.memoryFlush.softThresholdTokens",

src/config/schema.help.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,12 @@ export const FIELD_HELP: Record<string, string> = {
967967
'Identifier-preservation policy for compaction summaries: "strict" prepends built-in opaque-identifier retention guidance (default), "off" disables this prefix, and "custom" uses identifierInstructions. Keep "strict" unless you have a specific compatibility need.',
968968
"agents.defaults.compaction.identifierInstructions":
969969
'Custom identifier-preservation instruction text used when identifierPolicy="custom". Keep this explicit and safety-focused so compaction summaries do not rewrite opaque IDs, URLs, hosts, or ports.',
970+
"agents.defaults.compaction.qualityGuard":
971+
"Optional quality-audit retry settings for safeguard compaction summaries. Leave this disabled unless you explicitly want summary audits and one-shot regeneration on failed checks.",
972+
"agents.defaults.compaction.qualityGuard.enabled":
973+
"Enables summary quality audits and regeneration retries for safeguard compaction. Default: false, so safeguard mode alone does not turn on retry behavior.",
974+
"agents.defaults.compaction.qualityGuard.maxRetries":
975+
"Maximum number of regeneration retries after a failed safeguard summary quality audit. Use small values to bound extra latency and token cost.",
970976
"agents.defaults.compaction.memoryFlush":
971977
"Pre-compaction memory flush settings that run an agentic memory write before heavy compaction. Keep enabled for long sessions so salient context is persisted before aggressive trimming.",
972978
"agents.defaults.compaction.memoryFlush.enabled":

src/config/schema.labels.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,9 @@ export const FIELD_LABELS: Record<string, string> = {
434434
"agents.defaults.compaction.maxHistoryShare": "Compaction Max History Share",
435435
"agents.defaults.compaction.identifierPolicy": "Compaction Identifier Policy",
436436
"agents.defaults.compaction.identifierInstructions": "Compaction Identifier Instructions",
437+
"agents.defaults.compaction.qualityGuard": "Compaction Quality Guard",
438+
"agents.defaults.compaction.qualityGuard.enabled": "Compaction Quality Guard Enabled",
439+
"agents.defaults.compaction.qualityGuard.maxRetries": "Compaction Quality Guard Max Retries",
437440
"agents.defaults.compaction.memoryFlush": "Compaction Memory Flush",
438441
"agents.defaults.compaction.memoryFlush.enabled": "Compaction Memory Flush Enabled",
439442
"agents.defaults.compaction.memoryFlush.softThresholdTokens":

src/config/types.agent-defaults.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,12 @@ export type AgentDefaultsConfig = {
288288

289289
export type AgentCompactionMode = "default" | "safeguard";
290290
export type AgentCompactionIdentifierPolicy = "strict" | "off" | "custom";
291+
export type AgentCompactionQualityGuardConfig = {
292+
/** Enable compaction summary quality audits and regeneration retries. Default: false. */
293+
enabled?: boolean;
294+
/** Maximum regeneration retries after a failed quality audit. Default: 1 when enabled. */
295+
maxRetries?: number;
296+
};
291297

292298
export type AgentCompactionConfig = {
293299
/** Compaction summarization mode. */
@@ -304,6 +310,8 @@ export type AgentCompactionConfig = {
304310
identifierPolicy?: AgentCompactionIdentifierPolicy;
305311
/** Custom identifier-preservation instructions used when identifierPolicy is "custom". */
306312
identifierInstructions?: string;
313+
/** Optional quality-audit retries for safeguard compaction summaries. */
314+
qualityGuard?: AgentCompactionQualityGuardConfig;
307315
/** Pre-compaction memory flush (agentic turn). Default: enabled. */
308316
memoryFlush?: AgentCompactionMemoryFlushConfig;
309317
};

src/config/zod-schema.agent-defaults.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,13 @@ export const AgentDefaultsSchema = z
9595
.union([z.literal("strict"), z.literal("off"), z.literal("custom")])
9696
.optional(),
9797
identifierInstructions: z.string().optional(),
98+
qualityGuard: z
99+
.object({
100+
enabled: z.boolean().optional(),
101+
maxRetries: z.number().int().nonnegative().optional(),
102+
})
103+
.strict()
104+
.optional(),
98105
memoryFlush: z
99106
.object({
100107
enabled: z.boolean().optional(),

0 commit comments

Comments
 (0)