mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
test(cron): focus runtime config composition (#122867)
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
committed by
GitHub
parent
a5ff8f5c33
commit
2abe2e29bb
@@ -1,29 +1,18 @@
|
||||
// Direct delivery tests keep the active runtime config through isolated cron orchestration.
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { clearRuntimeConfigSnapshot, setRuntimeConfigSnapshot } from "../config/config.js";
|
||||
import {
|
||||
clearRuntimeConfigSnapshot,
|
||||
setRuntimeConfigSnapshot,
|
||||
} from "../config/runtime-snapshot.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import {
|
||||
makeIsolatedAgentJobFixture,
|
||||
makeIsolatedAgentParamsFixture,
|
||||
} from "./isolated-agent/job-fixtures.js";
|
||||
import { setupRunCronIsolatedAgentTurnSuite } from "./isolated-agent/run.suite-helpers.js";
|
||||
import {
|
||||
dispatchCronDeliveryMock,
|
||||
loadRunCronIsolatedAgentTurn,
|
||||
resolveCronDeliveryPlanMock,
|
||||
resolveDeliveryTargetMock,
|
||||
} from "./isolated-agent/run.test-harness.js";
|
||||
|
||||
const runCronIsolatedAgentTurn = await loadRunCronIsolatedAgentTurn();
|
||||
|
||||
describe("runCronIsolatedAgentTurn direct delivery config", () => {
|
||||
setupRunCronIsolatedAgentTurnSuite({ fast: true });
|
||||
import { resolveCronAgentConfig } from "./isolated-agent/run-config.js";
|
||||
|
||||
describe("resolveCronAgentConfig", () => {
|
||||
afterEach(() => {
|
||||
clearRuntimeConfigSnapshot();
|
||||
});
|
||||
|
||||
it("keeps the active runtime snapshot after agent-default derivation", async () => {
|
||||
it("keeps the active runtime snapshot after agent-default derivation", () => {
|
||||
const sourceCfg = {
|
||||
channels: {
|
||||
discord: {
|
||||
@@ -43,36 +32,14 @@ describe("runCronIsolatedAgentTurn direct delivery config", () => {
|
||||
},
|
||||
} satisfies OpenClawConfig;
|
||||
setRuntimeConfigSnapshot(runtimeCfg, sourceCfg);
|
||||
resolveCronDeliveryPlanMock.mockReturnValue({
|
||||
requested: true,
|
||||
mode: "announce",
|
||||
channel: "discord",
|
||||
to: "channel:789",
|
||||
});
|
||||
resolveDeliveryTargetMock.mockResolvedValue({
|
||||
ok: true,
|
||||
channel: "discord",
|
||||
to: "channel:789",
|
||||
accountId: undefined,
|
||||
threadId: undefined,
|
||||
mode: "explicit",
|
||||
|
||||
const { agentDefaults, cfgWithAgentDefaults, runtimeConfig } = resolveCronAgentConfig({
|
||||
config: sourceCfg,
|
||||
agentConfigOverride: { model: "openai/gpt-5.5" },
|
||||
});
|
||||
|
||||
const result = await runCronIsolatedAgentTurn(
|
||||
makeIsolatedAgentParamsFixture({
|
||||
cfg: sourceCfg,
|
||||
job: makeIsolatedAgentJobFixture({
|
||||
delivery: { mode: "announce", channel: "discord", to: "channel:789" },
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
expect(result).toMatchObject({ status: "ok", delivered: true });
|
||||
expect(dispatchCronDeliveryMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
cfg: sourceCfg,
|
||||
cfgWithAgentDefaults: expect.objectContaining({ channels: runtimeCfg.channels }),
|
||||
}),
|
||||
);
|
||||
expect(runtimeConfig).toBe(runtimeCfg);
|
||||
expect(agentDefaults.model).toEqual({ primary: "openai/gpt-5.5" });
|
||||
expect(cfgWithAgentDefaults.channels).toBe(runtimeCfg.channels);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ import { normalizeThinkLevel, type ThinkLevel } from "../../auto-reply/thinking.
|
||||
import type { AgentConfig } from "../../config/types.agents.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import type { CronJob } from "../types.js";
|
||||
import { buildCronAgentDefaultsConfig } from "./run-config.js";
|
||||
import { resolveCronAgentConfig } from "./run-config.js";
|
||||
import {
|
||||
DEFAULT_MODEL,
|
||||
DEFAULT_PROVIDER,
|
||||
@@ -199,14 +199,10 @@ export async function resolveCronModelSelection(
|
||||
? params.agentConfigOverride
|
||||
: resolveAgentConfig(owner.config, ownerAgentId)
|
||||
: undefined;
|
||||
const ownerAgentDefaults = buildCronAgentDefaultsConfig({
|
||||
defaults: owner.config.agents?.defaults,
|
||||
const { cfgWithAgentDefaults } = resolveCronAgentConfig({
|
||||
config: owner.config,
|
||||
agentConfigOverride: ownerAgentConfigOverride,
|
||||
});
|
||||
const cfgWithAgentDefaults: OpenClawConfig = {
|
||||
...owner.config,
|
||||
agents: Object.assign({}, owner.config.agents, { defaults: ownerAgentDefaults }),
|
||||
};
|
||||
const catalog = owner.modelCatalog.entries;
|
||||
const resolvedDefault = resolveConfiguredModelRef({
|
||||
cfg: cfgWithAgentDefaults,
|
||||
|
||||
@@ -52,21 +52,27 @@ function mergeCronAgentModelOverride(params: {
|
||||
return nextDefaults;
|
||||
}
|
||||
|
||||
/** Builds the agent defaults snapshot used by isolated cron runs. */
|
||||
export function buildCronAgentDefaultsConfig(params: {
|
||||
defaults?: AgentDefaultsConfig;
|
||||
/** Selects the active runtime snapshot before deriving isolated cron agent defaults. */
|
||||
export function resolveCronAgentConfig(params: {
|
||||
config: OpenClawConfig;
|
||||
agentConfigOverride?: ResolvedAgentConfig;
|
||||
}) {
|
||||
const runtimeConfig = resolveCronActiveRuntimeConfig(params.config);
|
||||
const { overrideModel, definedOverrides } = extractCronAgentDefaultsOverride(
|
||||
params.agentConfigOverride,
|
||||
);
|
||||
// Keep nested configs owned by agent-aware resolvers out of this flattened snapshot.
|
||||
// Copying partial sandbox or memory objects into defaults destroys their global
|
||||
// fields before the resolver can merge the selected agent's override.
|
||||
// Model authorization likewise uses the unflattened config plus agent id; this
|
||||
// snapshot only carries the effective runtime metadata and explicit policy.
|
||||
return mergeCronAgentModelOverride({
|
||||
defaults: Object.assign({}, params.defaults, definedOverrides),
|
||||
// Copying partial sandbox or memory objects into defaults destroys their global fields.
|
||||
const agentDefaults = mergeCronAgentModelOverride({
|
||||
defaults: Object.assign({}, runtimeConfig.agents?.defaults, definedOverrides),
|
||||
overrideModel,
|
||||
});
|
||||
return {
|
||||
runtimeConfig,
|
||||
agentDefaults,
|
||||
cfgWithAgentDefaults: {
|
||||
...runtimeConfig,
|
||||
agents: Object.assign({}, runtimeConfig.agents, { defaults: agentDefaults }),
|
||||
} satisfies OpenClawConfig,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
resolveCronModelSelectionOwner,
|
||||
resolveCronThinkingSelection,
|
||||
} from "./model-selection.js";
|
||||
import { buildCronAgentDefaultsConfig, resolveCronActiveRuntimeConfig } from "./run-config.js";
|
||||
import { resolveCronActiveRuntimeConfig, resolveCronAgentConfig } from "./run-config.js";
|
||||
import { buildCurrentConversationContextBlock } from "./run-current-context.js";
|
||||
import {
|
||||
createCronToolsAllowPreflightDiagnostics,
|
||||
@@ -165,13 +165,12 @@ export async function prepareCronRunContext(params: {
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
const runtimeCfg = modelOwner.config;
|
||||
const agentId = modelOwner.agentId;
|
||||
const agentDir = modelOwner.agentDir;
|
||||
const selectedAgentConfig = resolveAgentConfig(runtimeCfg, agentId);
|
||||
const selectedAgentConfig = resolveAgentConfig(modelOwner.config, agentId);
|
||||
const agentConfigOverride = normalizedRequested ? selectedAgentConfig : undefined;
|
||||
const agentCfg: AgentDefaultsConfig = buildCronAgentDefaultsConfig({
|
||||
defaults: runtimeCfg.agents?.defaults,
|
||||
const { runtimeConfig: runtimeCfg, agentDefaults: agentCfg } = resolveCronAgentConfig({
|
||||
config: modelOwner.config,
|
||||
agentConfigOverride,
|
||||
});
|
||||
const baseSessionKey = (input.sessionKey?.trim() || `cron:${input.job.id}`).trim();
|
||||
|
||||
@@ -2,9 +2,9 @@ import { describe, expect, it } from "vitest";
|
||||
import { resolveMemorySearchConfig } from "../../agents/memory-search.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import type { MemorySearchConfig } from "../../config/types.tools.js";
|
||||
import { buildCronAgentDefaultsConfig } from "./run-config.js";
|
||||
import { resolveCronAgentConfig } from "./run-config.js";
|
||||
|
||||
describe("buildCronAgentDefaultsConfig memory search preservation", () => {
|
||||
describe("resolveCronAgentConfig memory search preservation", () => {
|
||||
it("keeps global memory search defaults when the agent override is partial", () => {
|
||||
const defaultMemorySearch = {
|
||||
enabled: true,
|
||||
@@ -18,8 +18,8 @@ describe("buildCronAgentDefaultsConfig memory search preservation", () => {
|
||||
rememberAcrossConversations: true,
|
||||
query: { maxResults: 10 },
|
||||
} satisfies MemorySearchConfig;
|
||||
const agentDefaults = buildCronAgentDefaultsConfig({
|
||||
defaults: {},
|
||||
const { agentDefaults } = resolveCronAgentConfig({
|
||||
config: {},
|
||||
agentConfigOverride: { memory: { search: agentMemorySearch } },
|
||||
});
|
||||
const runCfg: OpenClawConfig = {
|
||||
|
||||
@@ -3,17 +3,13 @@ import { describe, expect, it } from "vitest";
|
||||
import { resolveAgentConfig } from "../../agents/agent-scope.js";
|
||||
import { resolveAllowedModelRefCore } from "../../agents/model-selection-resolve.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import { buildCronAgentDefaultsConfig } from "./run-config.js";
|
||||
import { resolveCronAgentConfig } from "./run-config.js";
|
||||
|
||||
function buildCronConfig(cfg: OpenClawConfig, agentId: string): OpenClawConfig {
|
||||
const defaults = buildCronAgentDefaultsConfig({
|
||||
defaults: cfg.agents?.defaults,
|
||||
return resolveCronAgentConfig({
|
||||
config: cfg,
|
||||
agentConfigOverride: resolveAgentConfig(cfg, agentId),
|
||||
});
|
||||
return {
|
||||
...cfg,
|
||||
agents: { ...cfg.agents, defaults },
|
||||
};
|
||||
}).cfgWithAgentDefaults;
|
||||
}
|
||||
|
||||
function resolveCronPayloadModel(cfg: OpenClawConfig, raw: string) {
|
||||
@@ -30,7 +26,7 @@ function resolveCronPayloadModel(cfg: OpenClawConfig, raw: string) {
|
||||
});
|
||||
}
|
||||
|
||||
describe("buildCronAgentDefaultsConfig model policy preservation", () => {
|
||||
describe("resolveCronAgentConfig model policy preservation", () => {
|
||||
it("keeps the inherited default restriction when the per-agent policy is empty", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
agents: {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Sandbox config preservation tests cover cron runs keeping sandbox settings intact.
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveSandboxConfigForAgent } from "../../agents/sandbox/config.js";
|
||||
import { buildCronAgentDefaultsConfig } from "./run-config.js";
|
||||
import { resolveCronAgentConfig } from "./run-config.js";
|
||||
|
||||
function makeCfg() {
|
||||
return {
|
||||
@@ -30,15 +30,14 @@ function makeCfg() {
|
||||
|
||||
function buildRunCfg(agentId: string, agentConfigOverride?: Record<string, unknown>) {
|
||||
const cfg = makeCfg();
|
||||
const agentDefaults = buildCronAgentDefaultsConfig({
|
||||
defaults: cfg.agents.defaults,
|
||||
const { cfgWithAgentDefaults } = resolveCronAgentConfig({
|
||||
config: cfg,
|
||||
agentConfigOverride: agentConfigOverride as never,
|
||||
});
|
||||
return {
|
||||
...cfg,
|
||||
...cfgWithAgentDefaults,
|
||||
agents: {
|
||||
...cfg.agents,
|
||||
defaults: agentDefaults,
|
||||
...cfgWithAgentDefaults.agents,
|
||||
list: [{ id: agentId, ...agentConfigOverride }],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -47,8 +47,8 @@ import { withPluginRuntimeRegistryScope } from "../plugins/runtime/gateway-reque
|
||||
import { getPluginToolMeta } from "../plugins/tools.js";
|
||||
import { normalizeAgentId } from "../routing/session-key.js";
|
||||
import {
|
||||
buildCronAgentDefaultsConfig,
|
||||
resolveCronActiveRuntimeConfig,
|
||||
resolveCronAgentConfig,
|
||||
} from "./isolated-agent/run-config.js";
|
||||
import { resolveCronAgentSessionKey } from "./isolated-agent/session-key.js";
|
||||
import {
|
||||
@@ -122,14 +122,10 @@ async function prepareTriggerRuntime(params: {
|
||||
const agentId = resolveTriggerAgentId(params.runtimeConfig, params.agentId);
|
||||
const selectedAgentConfig = resolveAgentConfig(params.runtimeConfig, agentId);
|
||||
const agentConfigOverride = params.agentId?.trim() ? selectedAgentConfig : undefined;
|
||||
const agentDefaults = buildCronAgentDefaultsConfig({
|
||||
defaults: params.runtimeConfig.agents?.defaults,
|
||||
const { agentDefaults, cfgWithAgentDefaults: config } = resolveCronAgentConfig({
|
||||
config: params.runtimeConfig,
|
||||
agentConfigOverride,
|
||||
});
|
||||
const config: OpenClawConfig = {
|
||||
...params.runtimeConfig,
|
||||
agents: Object.assign({}, params.runtimeConfig.agents, { defaults: agentDefaults }),
|
||||
};
|
||||
const workspaceDirRaw = resolveAgentWorkspaceDir(config, agentId);
|
||||
const agentDir = resolveAgentDir(config, agentId);
|
||||
const workspace = await ensureAgentWorkspace({
|
||||
|
||||
Reference in New Issue
Block a user