mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
fix: keep safeguard quality guard opt-in (openclaw#25556) thanks @rodrigouroz
This commit is contained in:
@@ -165,6 +165,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Plugin runtime/system: expose `runtime.system.requestHeartbeatNow(...)` so extensions can wake targeted sessions immediately after enqueueing system events. (#19464) Thanks @AustinEral.
|
||||
- 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.
|
||||
- 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.
|
||||
- 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.
|
||||
|
||||
### Breaking
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import compactionSafeguardExtension from "../pi-extensions/compaction-safeguard.
|
||||
import { buildEmbeddedExtensionFactories } from "./extensions.js";
|
||||
|
||||
describe("buildEmbeddedExtensionFactories", () => {
|
||||
it("wires safeguard quality-guard runtime flags", () => {
|
||||
it("does not opt safeguard mode into quality-guard retries", () => {
|
||||
const sessionManager = {} as SessionManager;
|
||||
const model = {
|
||||
id: "claude-sonnet-4-20250514",
|
||||
@@ -31,10 +31,44 @@ describe("buildEmbeddedExtensionFactories", () => {
|
||||
model,
|
||||
});
|
||||
|
||||
expect(factories).toContain(compactionSafeguardExtension);
|
||||
expect(getCompactionSafeguardRuntime(sessionManager)).toMatchObject({
|
||||
qualityGuardEnabled: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("wires explicit safeguard quality-guard runtime flags", () => {
|
||||
const sessionManager = {} as SessionManager;
|
||||
const model = {
|
||||
id: "claude-sonnet-4-20250514",
|
||||
contextWindow: 200_000,
|
||||
} as Model<Api>;
|
||||
const cfg = {
|
||||
agents: {
|
||||
defaults: {
|
||||
compaction: {
|
||||
mode: "safeguard",
|
||||
qualityGuard: {
|
||||
enabled: true,
|
||||
maxRetries: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const factories = buildEmbeddedExtensionFactories({
|
||||
cfg,
|
||||
sessionManager,
|
||||
provider: "anthropic",
|
||||
modelId: "claude-sonnet-4-20250514",
|
||||
model,
|
||||
});
|
||||
|
||||
expect(factories).toContain(compactionSafeguardExtension);
|
||||
expect(getCompactionSafeguardRuntime(sessionManager)).toMatchObject({
|
||||
qualityGuardEnabled: true,
|
||||
qualityGuardMaxRetries: 1,
|
||||
qualityGuardMaxRetries: 2,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -71,6 +71,7 @@ export function buildEmbeddedExtensionFactories(params: {
|
||||
const factories: ExtensionFactory[] = [];
|
||||
if (resolveCompactionMode(params.cfg) === "safeguard") {
|
||||
const compactionCfg = params.cfg?.agents?.defaults?.compaction;
|
||||
const qualityGuardCfg = compactionCfg?.qualityGuard;
|
||||
const contextWindowInfo = resolveContextWindowInfo({
|
||||
cfg: params.cfg,
|
||||
provider: params.provider,
|
||||
@@ -83,8 +84,8 @@ export function buildEmbeddedExtensionFactories(params: {
|
||||
contextWindowTokens: contextWindowInfo.tokens,
|
||||
identifierPolicy: compactionCfg?.identifierPolicy,
|
||||
identifierInstructions: compactionCfg?.identifierInstructions,
|
||||
qualityGuardEnabled: true,
|
||||
qualityGuardMaxRetries: 1,
|
||||
qualityGuardEnabled: qualityGuardCfg?.enabled ?? false,
|
||||
qualityGuardMaxRetries: qualityGuardCfg?.maxRetries,
|
||||
model: params.model,
|
||||
});
|
||||
factories.push(compactionSafeguardExtension);
|
||||
|
||||
@@ -13,6 +13,10 @@ describe("config compaction settings", () => {
|
||||
reserveTokensFloor: 12_345,
|
||||
identifierPolicy: "custom",
|
||||
identifierInstructions: "Keep ticket IDs unchanged.",
|
||||
qualityGuard: {
|
||||
enabled: true,
|
||||
maxRetries: 2,
|
||||
},
|
||||
memoryFlush: {
|
||||
enabled: false,
|
||||
softThresholdTokens: 1234,
|
||||
@@ -34,6 +38,8 @@ describe("config compaction settings", () => {
|
||||
expect(cfg.agents?.defaults?.compaction?.identifierInstructions).toBe(
|
||||
"Keep ticket IDs unchanged.",
|
||||
);
|
||||
expect(cfg.agents?.defaults?.compaction?.qualityGuard?.enabled).toBe(true);
|
||||
expect(cfg.agents?.defaults?.compaction?.qualityGuard?.maxRetries).toBe(2);
|
||||
expect(cfg.agents?.defaults?.compaction?.memoryFlush?.enabled).toBe(false);
|
||||
expect(cfg.agents?.defaults?.compaction?.memoryFlush?.softThresholdTokens).toBe(1234);
|
||||
expect(cfg.agents?.defaults?.compaction?.memoryFlush?.prompt).toBe("Write notes.");
|
||||
|
||||
@@ -370,6 +370,9 @@ const TARGET_KEYS = [
|
||||
"agents.defaults.compaction.maxHistoryShare",
|
||||
"agents.defaults.compaction.identifierPolicy",
|
||||
"agents.defaults.compaction.identifierInstructions",
|
||||
"agents.defaults.compaction.qualityGuard",
|
||||
"agents.defaults.compaction.qualityGuard.enabled",
|
||||
"agents.defaults.compaction.qualityGuard.maxRetries",
|
||||
"agents.defaults.compaction.memoryFlush",
|
||||
"agents.defaults.compaction.memoryFlush.enabled",
|
||||
"agents.defaults.compaction.memoryFlush.softThresholdTokens",
|
||||
|
||||
@@ -967,6 +967,12 @@ export const FIELD_HELP: Record<string, string> = {
|
||||
'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.',
|
||||
"agents.defaults.compaction.identifierInstructions":
|
||||
'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.',
|
||||
"agents.defaults.compaction.qualityGuard":
|
||||
"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.",
|
||||
"agents.defaults.compaction.qualityGuard.enabled":
|
||||
"Enables summary quality audits and regeneration retries for safeguard compaction. Default: false, so safeguard mode alone does not turn on retry behavior.",
|
||||
"agents.defaults.compaction.qualityGuard.maxRetries":
|
||||
"Maximum number of regeneration retries after a failed safeguard summary quality audit. Use small values to bound extra latency and token cost.",
|
||||
"agents.defaults.compaction.memoryFlush":
|
||||
"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.",
|
||||
"agents.defaults.compaction.memoryFlush.enabled":
|
||||
|
||||
@@ -434,6 +434,9 @@ export const FIELD_LABELS: Record<string, string> = {
|
||||
"agents.defaults.compaction.maxHistoryShare": "Compaction Max History Share",
|
||||
"agents.defaults.compaction.identifierPolicy": "Compaction Identifier Policy",
|
||||
"agents.defaults.compaction.identifierInstructions": "Compaction Identifier Instructions",
|
||||
"agents.defaults.compaction.qualityGuard": "Compaction Quality Guard",
|
||||
"agents.defaults.compaction.qualityGuard.enabled": "Compaction Quality Guard Enabled",
|
||||
"agents.defaults.compaction.qualityGuard.maxRetries": "Compaction Quality Guard Max Retries",
|
||||
"agents.defaults.compaction.memoryFlush": "Compaction Memory Flush",
|
||||
"agents.defaults.compaction.memoryFlush.enabled": "Compaction Memory Flush Enabled",
|
||||
"agents.defaults.compaction.memoryFlush.softThresholdTokens":
|
||||
|
||||
@@ -288,6 +288,12 @@ export type AgentDefaultsConfig = {
|
||||
|
||||
export type AgentCompactionMode = "default" | "safeguard";
|
||||
export type AgentCompactionIdentifierPolicy = "strict" | "off" | "custom";
|
||||
export type AgentCompactionQualityGuardConfig = {
|
||||
/** Enable compaction summary quality audits and regeneration retries. Default: false. */
|
||||
enabled?: boolean;
|
||||
/** Maximum regeneration retries after a failed quality audit. Default: 1 when enabled. */
|
||||
maxRetries?: number;
|
||||
};
|
||||
|
||||
export type AgentCompactionConfig = {
|
||||
/** Compaction summarization mode. */
|
||||
@@ -304,6 +310,8 @@ export type AgentCompactionConfig = {
|
||||
identifierPolicy?: AgentCompactionIdentifierPolicy;
|
||||
/** Custom identifier-preservation instructions used when identifierPolicy is "custom". */
|
||||
identifierInstructions?: string;
|
||||
/** Optional quality-audit retries for safeguard compaction summaries. */
|
||||
qualityGuard?: AgentCompactionQualityGuardConfig;
|
||||
/** Pre-compaction memory flush (agentic turn). Default: enabled. */
|
||||
memoryFlush?: AgentCompactionMemoryFlushConfig;
|
||||
};
|
||||
|
||||
@@ -95,6 +95,13 @@ export const AgentDefaultsSchema = z
|
||||
.union([z.literal("strict"), z.literal("off"), z.literal("custom")])
|
||||
.optional(),
|
||||
identifierInstructions: z.string().optional(),
|
||||
qualityGuard: z
|
||||
.object({
|
||||
enabled: z.boolean().optional(),
|
||||
maxRetries: z.number().int().nonnegative().optional(),
|
||||
})
|
||||
.strict()
|
||||
.optional(),
|
||||
memoryFlush: z
|
||||
.object({
|
||||
enabled: z.boolean().optional(),
|
||||
|
||||
Reference in New Issue
Block a user