mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 18:00:54 +00:00
fix(active-memory): make setup grace explicit
This commit is contained in:
@@ -36,6 +36,20 @@ describe("active-memory manifest config schema", () => {
|
||||
expect(result.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("accepts setupGraceTimeoutMs values at the runtime ceiling", () => {
|
||||
const result = validateJsonSchemaValue({
|
||||
schema: manifest.configSchema,
|
||||
cacheKey: "active-memory.manifest.setup-grace-timeout-ceiling",
|
||||
value: {
|
||||
enabled: true,
|
||||
agents: ["main"],
|
||||
setupGraceTimeoutMs: 30_000,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("accepts explicit in allowedChatTypes", () => {
|
||||
const result = validateJsonSchemaValue({
|
||||
schema: manifest.configSchema,
|
||||
@@ -64,6 +78,20 @@ describe("active-memory manifest config schema", () => {
|
||||
expect(result.ok).toBe(false);
|
||||
});
|
||||
|
||||
it("rejects setupGraceTimeoutMs values above the runtime ceiling", () => {
|
||||
const result = validateJsonSchemaValue({
|
||||
schema: manifest.configSchema,
|
||||
cacheKey: "active-memory.manifest.setup-grace-timeout-above-ceiling",
|
||||
value: {
|
||||
enabled: true,
|
||||
agents: ["main"],
|
||||
setupGraceTimeoutMs: 30_001,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
});
|
||||
|
||||
it("rejects unknown allowedChatTypes values", () => {
|
||||
const result = validateJsonSchemaValue({
|
||||
schema: manifest.configSchema,
|
||||
|
||||
@@ -185,18 +185,29 @@ describe("active-memory plugin", () => {
|
||||
|
||||
it("registers a before_prompt_build hook", () => {
|
||||
expect(api.on).toHaveBeenCalledWith("before_prompt_build", expect.any(Function), {
|
||||
timeoutMs: 45_000,
|
||||
timeoutMs: 15_000,
|
||||
});
|
||||
expect(hookOptions.before_prompt_build?.timeoutMs).toBe(45_000);
|
||||
expect(hookOptions.before_prompt_build?.timeoutMs).toBe(15_000);
|
||||
});
|
||||
|
||||
it("registers before_prompt_build with the configured recall timeout plus setup grace", () => {
|
||||
it("registers before_prompt_build with the configured recall timeout", () => {
|
||||
api.pluginConfig = {
|
||||
agents: ["main"],
|
||||
timeoutMs: 90_000,
|
||||
};
|
||||
plugin.register(api as unknown as OpenClawPluginApi);
|
||||
|
||||
expect(hookOptions.before_prompt_build?.timeoutMs).toBe(90_000);
|
||||
});
|
||||
|
||||
it("registers before_prompt_build with explicit setup grace when configured", () => {
|
||||
api.pluginConfig = {
|
||||
agents: ["main"],
|
||||
timeoutMs: 90_000,
|
||||
setupGraceTimeoutMs: 30_000,
|
||||
};
|
||||
plugin.register(api as unknown as OpenClawPluginApi);
|
||||
|
||||
expect(hookOptions.before_prompt_build?.timeoutMs).toBe(120_000);
|
||||
});
|
||||
|
||||
@@ -2178,10 +2189,10 @@ describe("active-memory plugin", () => {
|
||||
it("does not spend the model timeout budget on active-memory subagent setup", async () => {
|
||||
const CONFIGURED_TIMEOUT_MS = 10;
|
||||
__testing.setMinimumTimeoutMsForTests(1);
|
||||
__testing.setSetupGraceTimeoutMsForTests(100);
|
||||
api.pluginConfig = {
|
||||
agents: ["main"],
|
||||
timeoutMs: CONFIGURED_TIMEOUT_MS,
|
||||
setupGraceTimeoutMs: 100,
|
||||
logging: true,
|
||||
};
|
||||
plugin.register(api as unknown as OpenClawPluginApi);
|
||||
@@ -3242,6 +3253,16 @@ describe("active-memory plugin", () => {
|
||||
expect(config.circuitBreakerCooldownMs).toBe(60_000);
|
||||
});
|
||||
|
||||
it("normalizes setup grace config with a zero default and bounded opt-in", () => {
|
||||
expect(__testing.normalizePluginConfig({}).setupGraceTimeoutMs).toBe(0);
|
||||
expect(
|
||||
__testing.normalizePluginConfig({ setupGraceTimeoutMs: 30_001 }).setupGraceTimeoutMs,
|
||||
).toBe(30_000);
|
||||
expect(__testing.normalizePluginConfig({ setupGraceTimeoutMs: -1 }).setupGraceTimeoutMs).toBe(
|
||||
0,
|
||||
);
|
||||
});
|
||||
|
||||
it("clamps circuit breaker config within valid ranges", () => {
|
||||
const config = __testing.normalizePluginConfig({
|
||||
circuitBreakerMaxTimeouts: 0,
|
||||
|
||||
@@ -35,7 +35,7 @@ const DEFAULT_CACHE_TTL_MS = 15_000;
|
||||
const DEFAULT_MAX_CACHE_ENTRIES = 1000;
|
||||
const CACHE_SWEEP_INTERVAL_MS = 1000;
|
||||
const DEFAULT_MIN_TIMEOUT_MS = 250;
|
||||
const DEFAULT_SETUP_GRACE_TIMEOUT_MS = 30_000;
|
||||
const DEFAULT_SETUP_GRACE_TIMEOUT_MS = 0;
|
||||
const DEFAULT_QUERY_MODE = "recent" as const;
|
||||
const DEFAULT_QMD_SEARCH_MODE = "search" as const;
|
||||
const DEFAULT_TRANSCRIPT_DIR = "active-memory";
|
||||
@@ -91,6 +91,7 @@ type ActiveRecallPluginConfig = {
|
||||
promptOverride?: string;
|
||||
promptAppend?: string;
|
||||
timeoutMs?: number;
|
||||
setupGraceTimeoutMs?: number;
|
||||
queryMode?: "message" | "recent" | "full";
|
||||
maxSummaryChars?: number;
|
||||
recentUserTurns?: number;
|
||||
@@ -130,6 +131,7 @@ type ResolvedActiveRecallPluginConfig = {
|
||||
promptOverride?: string;
|
||||
promptAppend?: string;
|
||||
timeoutMs: number;
|
||||
setupGraceTimeoutMs: number;
|
||||
queryMode: "message" | "recent" | "full";
|
||||
maxSummaryChars: number;
|
||||
recentUserTurns: number;
|
||||
@@ -746,6 +748,7 @@ function normalizePluginConfig(pluginConfig: unknown): ResolvedActiveRecallPlugi
|
||||
minimumTimeoutMs,
|
||||
120_000,
|
||||
),
|
||||
setupGraceTimeoutMs: clampInt(raw.setupGraceTimeoutMs, setupGraceTimeoutMs, 0, 30_000),
|
||||
queryMode:
|
||||
raw.queryMode === "message" || raw.queryMode === "recent" || raw.queryMode === "full"
|
||||
? raw.queryMode
|
||||
@@ -2280,7 +2283,7 @@ async function maybeResolveActiveRecall(params: {
|
||||
const controller = new AbortController();
|
||||
const TIMEOUT_SENTINEL = Symbol("timeout");
|
||||
let sessionFile: string | undefined;
|
||||
const watchdogTimeoutMs = params.config.timeoutMs + setupGraceTimeoutMs;
|
||||
const watchdogTimeoutMs = params.config.timeoutMs + params.config.setupGraceTimeoutMs;
|
||||
const timeoutId = setTimeout(() => {
|
||||
controller.abort(new Error(`active-memory timeout after ${watchdogTimeoutMs}ms`));
|
||||
}, watchdogTimeoutMs);
|
||||
@@ -2535,7 +2538,7 @@ export default definePluginEntry({
|
||||
},
|
||||
});
|
||||
|
||||
const beforePromptBuildTimeoutMs = config.timeoutMs + setupGraceTimeoutMs;
|
||||
const beforePromptBuildTimeoutMs = config.timeoutMs + config.setupGraceTimeoutMs;
|
||||
api.on(
|
||||
"before_prompt_build",
|
||||
async (event, ctx) => {
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
"enum": ["off", "minimal", "low", "medium", "high", "xhigh", "adaptive"]
|
||||
},
|
||||
"timeoutMs": { "type": "integer", "minimum": 250, "maximum": 120000 },
|
||||
"setupGraceTimeoutMs": { "type": "integer", "minimum": 0, "maximum": 30000 },
|
||||
"queryMode": {
|
||||
"type": "string",
|
||||
"enum": ["message", "recent", "full"]
|
||||
@@ -116,6 +117,10 @@
|
||||
"timeoutMs": {
|
||||
"label": "Timeout (ms)"
|
||||
},
|
||||
"setupGraceTimeoutMs": {
|
||||
"label": "Setup Grace Timeout (ms)",
|
||||
"help": "Advanced: extra blocking budget for cold embedded-run setup before the recall timeout is considered exhausted. Defaults to 0 so timeoutMs remains the main-lane hook budget unless you opt in."
|
||||
},
|
||||
"queryMode": {
|
||||
"label": "Query Mode",
|
||||
"help": "Choose whether the blocking memory sub-agent sees only the latest user message, a small recent tail, or the full conversation."
|
||||
|
||||
Reference in New Issue
Block a user