refactor(cron): extract agent defaults merge helpers

This commit is contained in:
Peter Steinberger 2026-03-08 00:30:29 +00:00
parent 6b18ec479c
commit 45d3e62f50

View File

@ -94,6 +94,54 @@ export type RunCronAgentTurnResult = {
} & CronRunOutcome &
CronRunTelemetry;
type ResolvedAgentConfig = NonNullable<ReturnType<typeof resolveAgentConfig>>;
function extractCronAgentDefaultsOverride(agentConfigOverride?: ResolvedAgentConfig) {
const {
model: overrideModel,
sandbox: _agentSandboxOverride,
...agentOverrideRest
} = agentConfigOverride ?? {};
return {
overrideModel,
definedOverrides: Object.fromEntries(
Object.entries(agentOverrideRest).filter(([, value]) => value !== undefined),
) as Partial<AgentDefaultsConfig>,
};
}
function mergeCronAgentModelOverride(params: {
defaults: AgentDefaultsConfig;
overrideModel: ResolvedAgentConfig["model"] | undefined;
}) {
const nextDefaults: AgentDefaultsConfig = { ...params.defaults };
const existingModel =
nextDefaults.model && typeof nextDefaults.model === "object" ? nextDefaults.model : {};
if (typeof params.overrideModel === "string") {
nextDefaults.model = { ...existingModel, primary: params.overrideModel };
} else if (params.overrideModel) {
nextDefaults.model = { ...existingModel, ...params.overrideModel };
}
return nextDefaults;
}
function buildCronAgentDefaultsConfig(params: {
defaults?: AgentDefaultsConfig;
agentConfigOverride?: ResolvedAgentConfig;
}) {
const { overrideModel, definedOverrides } = extractCronAgentDefaultsOverride(
params.agentConfigOverride,
);
// Keep sandbox overrides out of `agents.defaults` here. Sandbox resolution
// already merges global defaults with per-agent overrides using `agentId`;
// copying the agent sandbox into defaults clobbers global defaults and can
// double-apply nested agent overrides during isolated cron runs.
return mergeCronAgentModelOverride({
defaults: Object.assign({}, params.defaults, definedOverrides),
overrideModel,
});
}
export async function runCronIsolatedAgentTurn(params: {
cfg: OpenClawConfig;
deps: CliDeps;
@ -125,36 +173,14 @@ export async function runCronIsolatedAgentTurn(params: {
const agentConfigOverride = normalizedRequested
? resolveAgentConfig(params.cfg, normalizedRequested)
: undefined;
const {
model: overrideModel,
sandbox: _agentSandboxOverride,
...agentOverrideRest
} = agentConfigOverride ?? {};
// Use the requested agentId even when there is no explicit agent config entry.
// This ensures auth-profiles, workspace, and agentDir all resolve to the
// correct per-agent paths (e.g. ~/.openclaw/agents/<agentId>/agent/).
const agentId = normalizedRequested ?? defaultAgentId;
// Keep sandbox overrides out of `agents.defaults` here. Sandbox resolution
// already merges global defaults with per-agent overrides using `agentId`;
// copying the agent sandbox into defaults clobbers global defaults and can
// double-apply nested agent overrides during isolated cron runs.
const definedOverrides = Object.fromEntries(
Object.entries(agentOverrideRest).filter(([, value]) => value !== undefined),
);
const agentCfg: AgentDefaultsConfig = Object.assign(
{},
params.cfg.agents?.defaults,
definedOverrides as Partial<AgentDefaultsConfig>,
);
// Merge agent model override with defaults instead of replacing, so that
// `fallbacks` from `agents.defaults.model` are preserved when the agent
// (or its per-cron model pin) only specifies `primary`.
const existingModel = agentCfg.model && typeof agentCfg.model === "object" ? agentCfg.model : {};
if (typeof overrideModel === "string") {
agentCfg.model = { ...existingModel, primary: overrideModel };
} else if (overrideModel) {
agentCfg.model = { ...existingModel, ...overrideModel };
}
const agentCfg = buildCronAgentDefaultsConfig({
defaults: params.cfg.agents?.defaults,
agentConfigOverride,
});
const cfgWithAgentDefaults: OpenClawConfig = {
...params.cfg,
agents: Object.assign({}, params.cfg.agents, { defaults: agentCfg }),