mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 20:24:46 +00:00
fix(config): materialize subagent archive default (#81998)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import fsSync, { promises as fs } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { DEFAULT_SUBAGENT_ARCHIVE_AFTER_MINUTES } from "../config/agent-limits.js";
|
||||
import { getRuntimeConfig } from "../config/config.js";
|
||||
import {
|
||||
loadSessionStore,
|
||||
@@ -345,7 +346,9 @@ export function reconcileOrphanedRestoredRuns(params: {
|
||||
|
||||
export function resolveArchiveAfterMs(cfg?: OpenClawConfig) {
|
||||
const config = cfg ?? getRuntimeConfig();
|
||||
const minutes = config.agents?.defaults?.subagents?.archiveAfterMinutes ?? 60;
|
||||
const minutes =
|
||||
config.agents?.defaults?.subagents?.archiveAfterMinutes ??
|
||||
DEFAULT_SUBAGENT_ARCHIVE_AFTER_MINUTES;
|
||||
if (!Number.isFinite(minutes) || minutes < 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -950,6 +950,26 @@ describe("config cli", () => {
|
||||
|
||||
expect(mockLog).toHaveBeenCalledWith("__OPENCLAW_REDACTED__");
|
||||
});
|
||||
|
||||
it("prints materialized subagent archive default", async () => {
|
||||
const resolved: OpenClawConfig = {};
|
||||
const config: OpenClawConfig = {
|
||||
agents: {
|
||||
defaults: {
|
||||
maxConcurrent: 4,
|
||||
subagents: {
|
||||
maxConcurrent: 8,
|
||||
archiveAfterMinutes: 60,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
setSnapshot(resolved, config);
|
||||
|
||||
await runConfigCommand(["config", "get", "agents.defaults.subagents.archiveAfterMinutes"]);
|
||||
|
||||
expect(mockLog).toHaveBeenCalledWith("60");
|
||||
});
|
||||
});
|
||||
|
||||
describe("config validate", () => {
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { OpenClawConfig } from "./types.js";
|
||||
export const DEFAULT_AGENT_MAX_CONCURRENT = 4;
|
||||
export const DEFAULT_SUBAGENT_MAX_CONCURRENT = 8;
|
||||
export const DEFAULT_SUBAGENT_MAX_CHILDREN_PER_AGENT = 5;
|
||||
export const DEFAULT_SUBAGENT_ARCHIVE_AFTER_MINUTES = 60;
|
||||
// Keep depth-1 subagents as leaves unless config explicitly opts into nesting.
|
||||
export const DEFAULT_SUBAGENT_MAX_SPAWN_DEPTH = 1;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
DEFAULT_AGENT_MAX_CONCURRENT,
|
||||
DEFAULT_SUBAGENT_ARCHIVE_AFTER_MINUTES,
|
||||
DEFAULT_SUBAGENT_MAX_CONCURRENT,
|
||||
resolveAgentMaxConcurrent,
|
||||
resolveSubagentMaxConcurrent,
|
||||
@@ -48,5 +49,8 @@ describe("agent concurrency defaults", () => {
|
||||
|
||||
expect(cfg.agents?.defaults?.maxConcurrent).toBe(DEFAULT_AGENT_MAX_CONCURRENT);
|
||||
expect(cfg.agents?.defaults?.subagents?.maxConcurrent).toBe(DEFAULT_SUBAGENT_MAX_CONCURRENT);
|
||||
expect(cfg.agents?.defaults?.subagents?.archiveAfterMinutes).toBe(
|
||||
DEFAULT_SUBAGENT_ARCHIVE_AFTER_MINUTES,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { DEFAULT_AGENT_MAX_CONCURRENT, DEFAULT_SUBAGENT_MAX_CONCURRENT } from "./agent-limits.js";
|
||||
import {
|
||||
DEFAULT_AGENT_MAX_CONCURRENT,
|
||||
DEFAULT_SUBAGENT_ARCHIVE_AFTER_MINUTES,
|
||||
DEFAULT_SUBAGENT_MAX_CONCURRENT,
|
||||
} from "./agent-limits.js";
|
||||
import {
|
||||
applyAgentDefaults,
|
||||
applyContextPruningDefaults,
|
||||
@@ -112,5 +116,17 @@ describe("config defaults", () => {
|
||||
|
||||
expect(next.agents?.defaults?.maxConcurrent).toBe(DEFAULT_AGENT_MAX_CONCURRENT);
|
||||
expect(next.agents?.defaults?.subagents?.maxConcurrent).toBe(DEFAULT_SUBAGENT_MAX_CONCURRENT);
|
||||
expect(next.agents?.defaults?.subagents?.archiveAfterMinutes).toBe(
|
||||
DEFAULT_SUBAGENT_ARCHIVE_AFTER_MINUTES,
|
||||
);
|
||||
});
|
||||
|
||||
it("preserves explicit subagent archive default", () => {
|
||||
const next = applyAgentDefaults({
|
||||
agents: { defaults: { subagents: { archiveAfterMinutes: 0 } } },
|
||||
} as never);
|
||||
|
||||
expect(next.agents?.defaults?.subagents?.archiveAfterMinutes).toBe(0);
|
||||
expect(next.agents?.defaults?.subagents?.maxConcurrent).toBe(DEFAULT_SUBAGENT_MAX_CONCURRENT);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,11 @@ import { DEFAULT_CONTEXT_TOKENS } from "../agents/defaults.js";
|
||||
import { normalizeConfiguredProviderCatalogModelId } from "../agents/model-ref-shared.js";
|
||||
import { normalizeProviderId } from "../agents/provider-id.js";
|
||||
import type { PluginManifestRegistry } from "../plugins/manifest-registry.js";
|
||||
import { DEFAULT_AGENT_MAX_CONCURRENT, DEFAULT_SUBAGENT_MAX_CONCURRENT } from "./agent-limits.js";
|
||||
import {
|
||||
DEFAULT_AGENT_MAX_CONCURRENT,
|
||||
DEFAULT_SUBAGENT_ARCHIVE_AFTER_MINUTES,
|
||||
DEFAULT_SUBAGENT_MAX_CONCURRENT,
|
||||
} from "./agent-limits.js";
|
||||
import { normalizeAgentModelMapForConfig, normalizeAgentModelRefForConfig } from "./model-input.js";
|
||||
import {
|
||||
applyProviderConfigDefaultsForConfig,
|
||||
@@ -394,7 +398,10 @@ export function applyAgentDefaults(cfg: OpenClawConfig): OpenClawConfig {
|
||||
const hasSubMax =
|
||||
typeof defaults?.subagents?.maxConcurrent === "number" &&
|
||||
Number.isFinite(defaults.subagents.maxConcurrent);
|
||||
if (hasMax && hasSubMax) {
|
||||
const hasSubArchive =
|
||||
typeof defaults?.subagents?.archiveAfterMinutes === "number" &&
|
||||
Number.isFinite(defaults.subagents.archiveAfterMinutes);
|
||||
if (hasMax && hasSubMax && hasSubArchive) {
|
||||
return cfg;
|
||||
}
|
||||
|
||||
@@ -410,6 +417,10 @@ export function applyAgentDefaults(cfg: OpenClawConfig): OpenClawConfig {
|
||||
nextSubagents.maxConcurrent = DEFAULT_SUBAGENT_MAX_CONCURRENT;
|
||||
mutated = true;
|
||||
}
|
||||
if (!hasSubArchive) {
|
||||
nextSubagents.archiveAfterMinutes = DEFAULT_SUBAGENT_ARCHIVE_AFTER_MINUTES;
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (!mutated) {
|
||||
return cfg;
|
||||
|
||||
Reference in New Issue
Block a user