mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 09:41:11 +00:00
fix(memory-core): use startup config for dreaming cron reconciliation (#63873)
Merged via squash.
Prepared head SHA: 2ec22920cd
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
This commit is contained in:
@@ -29,6 +29,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Fireworks/FirePass: disable Kimi K2.5 Turbo reasoning output by forcing thinking off on the FirePass path and hardening the provider wrapper so hidden reasoning no longer leaks into visible replies. (#63607) Thanks @frankekn.
|
||||
- Sessions/model selection: preserve catalog-backed session model labels and keep already-qualified session model refs stable when catalog metadata is unavailable, so Control UI model selection survives reloads without bogus provider-prefixed values. (#61382) Thanks @Mule-ME.
|
||||
- Gateway/startup: keep WebSocket RPC available while channels and plugin sidecars start, hold `chat.history` unavailable until startup sidecars finish so synchronous history reads cannot stall startup (reported in #63450), refresh advertised gateway methods after deferred plugin reloads, and enforce the pre-auth WebSocket upgrade budget before the no-handler 503 path so upgrade floods cannot bypass connection limits during that window. (#63480) Thanks @neeravmakwana.
|
||||
- Dreaming/cron: reconcile managed dreaming cron from the resolved gateway startup config so boot-time schedule recovery respects the configured cadence and timezone. (#63873) Thanks @mbelinky.
|
||||
- Gateway/tailscale: start Tailscale exposure and the gateway update check before awaiting channel and plugin sidecar startup so remote operators are not locked out when startup sidecars stall.
|
||||
- QQBot/streaming: make block streaming configurable per QQ bot account via `streaming.mode` (`"partial"` | `"off"`, default `"partial"`) instead of hardcoding it off, so responses can be delivered incrementally. (#63746)
|
||||
- Dreaming/gateway: require `operator.admin` for persistent `/dreaming on|off` changes and treat missing gateway client scopes as unprivileged instead of silently allowing config writes. (#63872) Thanks @mbelinky.
|
||||
|
||||
@@ -2,9 +2,16 @@ import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/memory-core";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
clearInternalHooks,
|
||||
createInternalHookEvent,
|
||||
registerInternalHook,
|
||||
triggerInternalHook,
|
||||
} from "../../../src/hooks/internal-hooks.js";
|
||||
import {
|
||||
__testing,
|
||||
reconcileShortTermDreamingCronJob,
|
||||
registerShortTermPromotionDreaming,
|
||||
resolveShortTermPromotionDreamingConfig,
|
||||
runShortTermDreamingPromotionIfTriggered,
|
||||
} from "./dreaming.js";
|
||||
@@ -661,6 +668,63 @@ describe("short-term dreaming cron reconciliation", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("gateway startup reconciliation", () => {
|
||||
it("uses the startup cfg when reconciling the managed dreaming cron job", async () => {
|
||||
clearInternalHooks();
|
||||
const logger = createLogger();
|
||||
const harness = createCronHarness();
|
||||
const api = {
|
||||
config: { plugins: { entries: {} } },
|
||||
pluginConfig: {},
|
||||
logger,
|
||||
runtime: {},
|
||||
registerHook: (event: string, handler: Parameters<typeof registerInternalHook>[1]) => {
|
||||
registerInternalHook(event, handler);
|
||||
},
|
||||
on: vi.fn(),
|
||||
} as never;
|
||||
|
||||
try {
|
||||
registerShortTermPromotionDreaming(api);
|
||||
await triggerInternalHook(
|
||||
createInternalHookEvent("gateway", "startup", "gateway:startup", {
|
||||
cfg: {
|
||||
hooks: { internal: { enabled: true } },
|
||||
plugins: {
|
||||
entries: {
|
||||
"memory-core": {
|
||||
config: {
|
||||
dreaming: {
|
||||
enabled: true,
|
||||
frequency: "15 4 * * *",
|
||||
timezone: "UTC",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
deps: { cron: harness.cron },
|
||||
}),
|
||||
);
|
||||
|
||||
expect(harness.addCalls).toHaveLength(1);
|
||||
expect(harness.addCalls[0]).toMatchObject({
|
||||
schedule: {
|
||||
kind: "cron",
|
||||
expr: "15 4 * * *",
|
||||
tz: "UTC",
|
||||
},
|
||||
});
|
||||
expect(logger.info).toHaveBeenCalledWith(
|
||||
expect.stringContaining("created managed dreaming cron job"),
|
||||
);
|
||||
} finally {
|
||||
clearInternalHooks();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("short-term dreaming trigger", () => {
|
||||
it("applies promotions when the managed dreaming heartbeat event fires", async () => {
|
||||
const logger = createLogger();
|
||||
|
||||
@@ -307,6 +307,16 @@ function resolveCronServiceFromStartupEvent(event: unknown): CronServiceLike | n
|
||||
return cron as CronServiceLike;
|
||||
}
|
||||
|
||||
function resolveStartupConfigFromEvent(event: unknown, fallback: OpenClawConfig): OpenClawConfig {
|
||||
const startupEvent = asRecord(event);
|
||||
const startupContext = asRecord(startupEvent?.context);
|
||||
const startupCfg = asRecord(startupContext?.cfg);
|
||||
if (!startupCfg) {
|
||||
return fallback;
|
||||
}
|
||||
return startupCfg as OpenClawConfig;
|
||||
}
|
||||
|
||||
export function resolveShortTermPromotionDreamingConfig(params: {
|
||||
pluginConfig?: Record<string, unknown>;
|
||||
cfg?: OpenClawConfig;
|
||||
@@ -584,9 +594,14 @@ export function registerShortTermPromotionDreaming(api: OpenClawPluginApi): void
|
||||
"gateway:startup",
|
||||
async (event: unknown) => {
|
||||
try {
|
||||
// Use the resolved startup snapshot so cron reconciliation matches the boot config.
|
||||
const startupCfg = resolveStartupConfigFromEvent(event, api.config);
|
||||
const config = resolveShortTermPromotionDreamingConfig({
|
||||
pluginConfig: resolveMemoryCorePluginConfig(api.config) ?? api.pluginConfig,
|
||||
cfg: api.config,
|
||||
pluginConfig:
|
||||
resolveMemoryCorePluginConfig(startupCfg) ??
|
||||
resolveMemoryCorePluginConfig(api.config) ??
|
||||
api.pluginConfig,
|
||||
cfg: startupCfg,
|
||||
});
|
||||
const cron = resolveCronServiceFromStartupEvent(event);
|
||||
if (!cron && config.enabled) {
|
||||
|
||||
Reference in New Issue
Block a user