From 10fcfd994cab0e54a85d1e77629eaa6bd08ce54c Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sun, 31 May 2026 10:30:56 +0900 Subject: [PATCH] fix(codex): remove legacy agent thread cap --- .../omo-codex/scripts/install-config.test.mjs | 70 +++++++++++++++++++ .../scripts/install/multi-agent-v2-config.mjs | 8 ++- .../install-codex/codex-config-toml.test.ts | 70 +++++++++++++++++++ .../codex-multi-agent-v2-config.ts | 8 ++- 4 files changed, 154 insertions(+), 2 deletions(-) diff --git a/packages/omo-codex/scripts/install-config.test.mjs b/packages/omo-codex/scripts/install-config.test.mjs index f984b3dc5..7e2933bba 100644 --- a/packages/omo-codex/scripts/install-config.test.mjs +++ b/packages/omo-codex/scripts/install-config.test.mjs @@ -171,3 +171,73 @@ test("#given legacy boolean MultiAgentV2 flag and table #when script installer u assert.match(config, /usage_hint_enabled = false/); assert.match(config, /max_concurrent_threads_per_session = 10000/); }); + +test("#given legacy agents max_threads #when script installer updates config #then removes the conflicting legacy thread cap", async () => { + // given + const root = await mkdtemp(join(tmpdir(), "omo-codex-script-config-multi-agent-legacy-threads-")); + const configPath = join(root, "config.toml"); + await writeFile( + configPath, + [ + "[agents]", + "max_threads = 16", + "max_depth = 4", + "job_max_runtime_seconds = 3600", + "", + ].join("\n"), + ); + + // when + await updateCodexConfig({ + configPath, + repoRoot: "/repo/packages/omo-codex", + marketplaceName: "debug", + marketplaceSource: { sourceType: "local", source: "/repo/packages/omo-codex" }, + pluginNames: ["omo"], + }); + + // then + const config = await readFile(configPath, "utf8"); + assert.match(config, /\[features\.multi_agent_v2\]/); + assert.match(config, /enabled = true/); + assert.match(config, /max_concurrent_threads_per_session = 10000/); + assert.match(config, /\[agents\]/); + assert.doesNotMatch(config, /^max_threads\s*=/m); + assert.match(config, /max_depth = 4/); + assert.match(config, /job_max_runtime_seconds = 3600/); +}); + +test("#given managed agent role sections #when script installer updates config #then preserves role config while removing only root agents max_threads", async () => { + // given + const root = await mkdtemp(join(tmpdir(), "omo-codex-script-config-multi-agent-role-section-")); + const configPath = join(root, "config.toml"); + await writeFile( + configPath, + [ + "[agents]", + "max_threads = 16", + "", + "[agents.explorer]", + 'description = "read-only explorer"', + 'config_file = "./agents/explorer.toml"', + "", + ].join("\n"), + ); + + // when + await updateCodexConfig({ + configPath, + repoRoot: "/repo/packages/omo-codex", + marketplaceName: "debug", + marketplaceSource: { sourceType: "local", source: "/repo/packages/omo-codex" }, + pluginNames: ["omo"], + agentConfigs: [{ name: "explorer", configFile: "./agents/explorer.toml" }], + }); + + // then + const config = await readFile(configPath, "utf8"); + assert.doesNotMatch(config, /^max_threads\s*=/m); + assert.match(config, /\[agents\.explorer\]/); + assert.match(config, /description = "read-only explorer"/); + assert.match(config, /config_file = "\.\/agents\/explorer\.toml"/); +}); diff --git a/packages/omo-codex/scripts/install/multi-agent-v2-config.mjs b/packages/omo-codex/scripts/install/multi-agent-v2-config.mjs index 168771a11..b0299158c 100644 --- a/packages/omo-codex/scripts/install/multi-agent-v2-config.mjs +++ b/packages/omo-codex/scripts/install/multi-agent-v2-config.mjs @@ -4,7 +4,7 @@ const CODEX_MULTI_AGENT_V2_HEADER = "features.multi_agent_v2"; const CODEX_MULTI_AGENT_V2_MAX_CONCURRENT_THREADS_PER_SESSION = 10000; export function ensureCodexMultiAgentV2Config(config) { - const normalizedConfig = removeFeatureFlagSetting(config, "multi_agent_v2"); + const normalizedConfig = removeLegacyAgentsMaxThreadsSetting(removeFeatureFlagSetting(config, "multi_agent_v2")); const section = findTomlSection(normalizedConfig, CODEX_MULTI_AGENT_V2_HEADER); const maxThreadsValue = CODEX_MULTI_AGENT_V2_MAX_CONCURRENT_THREADS_PER_SESSION.toString(); if (!section) { @@ -30,3 +30,9 @@ function removeFeatureFlagSetting(config, featureName) { if (!section) return config; return removeSetting(config, section, featureName); } + +function removeLegacyAgentsMaxThreadsSetting(config) { + const section = findTomlSection(config, "agents"); + if (!section) return config; + return removeSetting(config, section, "max_threads"); +} diff --git a/src/cli/install-codex/codex-config-toml.test.ts b/src/cli/install-codex/codex-config-toml.test.ts index 8997379e2..444187759 100644 --- a/src/cli/install-codex/codex-config-toml.test.ts +++ b/src/cli/install-codex/codex-config-toml.test.ts @@ -146,6 +146,76 @@ describe("codex-config-toml", () => { expect(content).toContain("max_concurrent_threads_per_session = 10000") }) + test("#given legacy agents max_threads #when updating config #then removes the conflicting legacy thread cap", async () => { + // given + const root = await mkdtemp(join(tmpdir(), "omo-codex-config-multi-agent-legacy-threads-")) + const configPath = join(root, "config.toml") + await writeFile( + configPath, + [ + "[agents]", + "max_threads = 16", + "max_depth = 4", + "job_max_runtime_seconds = 3600", + "", + ].join("\n"), + ) + + // when + await updateCodexConfig({ + configPath, + repoRoot: "/repo/packages/omo-codex", + marketplaceName: "debug", + marketplaceSource: { sourceType: "local", source: "/repo/packages/omo-codex" }, + pluginNames: ["omo"], + }) + + // then + const content = await readFile(configPath, "utf8") + expect(content).toContain("[features.multi_agent_v2]") + expect(content).toContain("enabled = true") + expect(content).toContain("max_concurrent_threads_per_session = 10000") + expect(content).toContain("[agents]") + expect(content).not.toMatch(/^max_threads\s*=/m) + expect(content).toContain("max_depth = 4") + expect(content).toContain("job_max_runtime_seconds = 3600") + }) + + test("#given managed agent role sections #when updating config #then preserves role config while removing only root agents max_threads", async () => { + // given + const root = await mkdtemp(join(tmpdir(), "omo-codex-config-multi-agent-role-section-")) + const configPath = join(root, "config.toml") + await writeFile( + configPath, + [ + "[agents]", + "max_threads = 16", + "", + "[agents.explorer]", + 'description = "read-only explorer"', + 'config_file = "./agents/explorer.toml"', + "", + ].join("\n"), + ) + + // when + await updateCodexConfig({ + configPath, + repoRoot: "/repo/packages/omo-codex", + marketplaceName: "debug", + marketplaceSource: { sourceType: "local", source: "/repo/packages/omo-codex" }, + pluginNames: ["omo"], + agentConfigs: [{ name: "explorer", configFile: "./agents/explorer.toml" }], + }) + + // then + const content = await readFile(configPath, "utf8") + expect(content).not.toMatch(/^max_threads\s*=/m) + expect(content).toContain("[agents.explorer]") + expect(content).toContain('description = "read-only explorer"') + expect(content).toContain('config_file = "./agents/explorer.toml"') + }) + test("writes config blocks and stays idempotent", async () => { // given const root = await mkdtemp(join(tmpdir(), "omo-codex-config-")) diff --git a/src/cli/install-codex/codex-multi-agent-v2-config.ts b/src/cli/install-codex/codex-multi-agent-v2-config.ts index 76b1b65eb..7f630ce1a 100644 --- a/src/cli/install-codex/codex-multi-agent-v2-config.ts +++ b/src/cli/install-codex/codex-multi-agent-v2-config.ts @@ -4,7 +4,7 @@ const CODEX_MULTI_AGENT_V2_HEADER = "features.multi_agent_v2" const CODEX_MULTI_AGENT_V2_MAX_CONCURRENT_THREADS_PER_SESSION = 10000 export function ensureCodexMultiAgentV2Config(config: string): string { - const normalizedConfig = removeFeatureFlagSetting(config, "multi_agent_v2") + const normalizedConfig = removeLegacyAgentsMaxThreadsSetting(removeFeatureFlagSetting(config, "multi_agent_v2")) const section = findTomlSection(normalizedConfig, CODEX_MULTI_AGENT_V2_HEADER) const maxThreadsValue = CODEX_MULTI_AGENT_V2_MAX_CONCURRENT_THREADS_PER_SESSION.toString() if (!section) { @@ -30,3 +30,9 @@ function removeFeatureFlagSetting(config: string, featureName: string): string { if (!section) return config return removeSetting(config, section, featureName) } + +function removeLegacyAgentsMaxThreadsSetting(config: string): string { + const section = findTomlSection(config, "agents") + if (!section) return config + return removeSetting(config, section, "max_threads") +}