refactor: centralize agent concurrency defaults

This commit is contained in:
Peter Steinberger
2026-01-20 10:27:58 +00:00
parent d88b239d3c
commit 213d9b47b0
8 changed files with 79 additions and 11 deletions

View File

@@ -7,6 +7,7 @@ Docs: https://docs.clawd.bot
### Changes
- Repo: remove the Peekaboo git submodule now that the SPM release is used.
- Gateway: raise default lane concurrency for main and sub-agent runs.
- Config: centralize default agent concurrency limits.
### Fixes
- Web search: infer Perplexity base URL from API key source (direct vs OpenRouter).

View File

@@ -0,0 +1,2 @@
export const DEFAULT_AGENT_MAX_CONCURRENT = 4;
export const DEFAULT_SUBAGENT_MAX_CONCURRENT = 8;

View File

@@ -1,5 +1,6 @@
import { resolveTalkApiKey } from "./talk.js";
import type { ClawdbotConfig } from "./types.js";
import { DEFAULT_AGENT_MAX_CONCURRENT, DEFAULT_SUBAGENT_MAX_CONCURRENT } from "./agent-limits.js";
type WarnState = { warned: boolean };
@@ -105,6 +106,43 @@ export function applyModelDefaults(cfg: ClawdbotConfig): ClawdbotConfig {
};
}
export function applyAgentDefaults(cfg: ClawdbotConfig): ClawdbotConfig {
const agents = cfg.agents;
const defaults = agents?.defaults;
const hasMax =
typeof defaults?.maxConcurrent === "number" && Number.isFinite(defaults.maxConcurrent);
const hasSubMax =
typeof defaults?.subagents?.maxConcurrent === "number" &&
Number.isFinite(defaults.subagents.maxConcurrent);
if (hasMax && hasSubMax) return cfg;
let mutated = false;
const nextDefaults = defaults ? { ...defaults } : {};
if (!hasMax) {
nextDefaults.maxConcurrent = DEFAULT_AGENT_MAX_CONCURRENT;
mutated = true;
}
const nextSubagents = defaults?.subagents ? { ...defaults.subagents } : {};
if (!hasSubMax) {
nextSubagents.maxConcurrent = DEFAULT_SUBAGENT_MAX_CONCURRENT;
mutated = true;
}
if (!mutated) return cfg;
return {
...cfg,
agents: {
...agents,
defaults: {
...nextDefaults,
subagents: nextSubagents,
},
},
};
}
export function applyLoggingDefaults(cfg: ClawdbotConfig): ClawdbotConfig {
const logging = cfg.logging;
if (!logging) return cfg;

View File

@@ -15,6 +15,7 @@ import { DuplicateAgentDirError, findDuplicateAgentDirs } from "./agent-dirs.js"
import {
applyCompactionDefaults,
applyContextPruningDefaults,
applyAgentDefaults,
applyLoggingDefaults,
applyMessageDefaults,
applyModelDefaults,
@@ -244,8 +245,10 @@ export function createConfigIO(overrides: ConfigIoDeps = {}) {
const cfg = applyModelDefaults(
applyCompactionDefaults(
applyContextPruningDefaults(
applySessionDefaults(
applyLoggingDefaults(applyMessageDefaults(validated.data as ClawdbotConfig)),
applyAgentDefaults(
applySessionDefaults(
applyLoggingDefaults(applyMessageDefaults(validated.data as ClawdbotConfig)),
),
),
),
),
@@ -291,7 +294,9 @@ export function createConfigIO(overrides: ConfigIoDeps = {}) {
const config = applyTalkApiKey(
applyModelDefaults(
applyCompactionDefaults(
applyContextPruningDefaults(applySessionDefaults(applyMessageDefaults({}))),
applyContextPruningDefaults(
applyAgentDefaults(applySessionDefaults(applyMessageDefaults({}))),
),
),
),
);
@@ -402,7 +407,9 @@ export function createConfigIO(overrides: ConfigIoDeps = {}) {
config: normalizeConfigPaths(
applyTalkApiKey(
applyModelDefaults(
applySessionDefaults(applyLoggingDefaults(applyMessageDefaults(validated.config))),
applyAgentDefaults(
applySessionDefaults(applyLoggingDefaults(applyMessageDefaults(validated.config))),
),
),
),
),

View File

@@ -1,5 +1,5 @@
import { findDuplicateAgentDirs, formatDuplicateAgentDirError } from "./agent-dirs.js";
import { applyModelDefaults, applySessionDefaults } from "./defaults.js";
import { applyAgentDefaults, applyModelDefaults, applySessionDefaults } from "./defaults.js";
import { findLegacyConfigIssues } from "./legacy.js";
import type { ClawdbotConfig, ConfigValidationIssue } from "./types.js";
import { ClawdbotSchema } from "./zod-schema.js";
@@ -41,6 +41,8 @@ export function validateConfigObject(
}
return {
ok: true,
config: applyModelDefaults(applySessionDefaults(validated.data as ClawdbotConfig)),
config: applyModelDefaults(
applyAgentDefaults(applySessionDefaults(validated.data as ClawdbotConfig)),
),
};
}

View File

@@ -1,8 +1,18 @@
import type { loadConfig } from "../config/config.js";
import {
DEFAULT_AGENT_MAX_CONCURRENT,
DEFAULT_SUBAGENT_MAX_CONCURRENT,
} from "../config/agent-limits.js";
import { setCommandLaneConcurrency } from "../process/command-queue.js";
export function applyGatewayLaneConcurrency(cfg: ReturnType<typeof loadConfig>) {
setCommandLaneConcurrency("cron", cfg.cron?.maxConcurrentRuns ?? 1);
setCommandLaneConcurrency("main", cfg.agents?.defaults?.maxConcurrent ?? 4);
setCommandLaneConcurrency("subagent", cfg.agents?.defaults?.subagents?.maxConcurrent ?? 8);
setCommandLaneConcurrency(
"main",
cfg.agents?.defaults?.maxConcurrent ?? DEFAULT_AGENT_MAX_CONCURRENT,
);
setCommandLaneConcurrency(
"subagent",
cfg.agents?.defaults?.subagents?.maxConcurrent ?? DEFAULT_SUBAGENT_MAX_CONCURRENT,
);
}

View File

@@ -8,6 +8,10 @@ import {
setGatewaySigusr1RestartPolicy,
} from "../infra/restart.js";
import { setCommandLaneConcurrency } from "../process/command-queue.js";
import {
DEFAULT_AGENT_MAX_CONCURRENT,
DEFAULT_SUBAGENT_MAX_CONCURRENT,
} from "../config/agent-limits.js";
import { isTruthyEnvValue } from "../infra/env.js";
import type { ChannelKind, GatewayReloadPlan } from "./config-reload.js";
import { resolveHooksConfig } from "./hooks.js";
@@ -127,10 +131,13 @@ export function createGatewayReloadHandlers(params: {
}
setCommandLaneConcurrency("cron", nextConfig.cron?.maxConcurrentRuns ?? 1);
setCommandLaneConcurrency("main", nextConfig.agents?.defaults?.maxConcurrent ?? 4);
setCommandLaneConcurrency(
"main",
nextConfig.agents?.defaults?.maxConcurrent ?? DEFAULT_AGENT_MAX_CONCURRENT,
);
setCommandLaneConcurrency(
"subagent",
nextConfig.agents?.defaults?.subagents?.maxConcurrent ?? 8,
nextConfig.agents?.defaults?.subagents?.maxConcurrent ?? DEFAULT_SUBAGENT_MAX_CONCURRENT,
);
if (plan.hotReasons.length > 0) {

View File

@@ -1,6 +1,7 @@
import { type RunOptions, run } from "@grammyjs/runner";
import type { ClawdbotConfig } from "../config/config.js";
import { loadConfig } from "../config/config.js";
import { DEFAULT_AGENT_MAX_CONCURRENT } from "../config/agent-limits.js";
import { computeBackoff, sleepWithAbort } from "../infra/backoff.js";
import { formatDurationMs } from "../infra/format-duration.js";
import type { RuntimeEnv } from "../runtime.js";
@@ -28,7 +29,7 @@ export type MonitorTelegramOpts = {
export function createTelegramRunnerOptions(cfg: ClawdbotConfig): RunOptions<unknown> {
return {
sink: {
concurrency: cfg.agents?.defaults?.maxConcurrent ?? 1,
concurrency: cfg.agents?.defaults?.maxConcurrent ?? DEFAULT_AGENT_MAX_CONCURRENT,
},
runner: {
fetch: {