diff --git a/src/__tests__/subagentAutoBackground.test.ts b/src/__tests__/subagentAutoBackground.test.ts new file mode 100644 index 0000000..4a2814a --- /dev/null +++ b/src/__tests__/subagentAutoBackground.test.ts @@ -0,0 +1,51 @@ +/** + * item 12: 子代理自动后台化阈值解析单测 (CC 2.1.198/232) + */ +import { describe, expect, it } from "bun:test"; +import { getSubagentAutoBackgroundMs } from "../tools/AgentTool/autoBackground.js"; + +describe("getSubagentAutoBackgroundMs", () => { + const orig = process.env.FUSION_SUBAGENT_AUTO_BACKGROUND_MS; + + it("未设 → 0 (default off, byte-identical 旧行为)", () => { + delete process.env.FUSION_SUBAGENT_AUTO_BACKGROUND_MS; + expect(getSubagentAutoBackgroundMs()).toBe(0); + }); + + it("空串 → 0", () => { + process.env.FUSION_SUBAGENT_AUTO_BACKGROUND_MS = ""; + expect(getSubagentAutoBackgroundMs()).toBe(0); + }); + + it("正值 60000 → 60000", () => { + process.env.FUSION_SUBAGENT_AUTO_BACKGROUND_MS = "60000"; + expect(getSubagentAutoBackgroundMs()).toBe(60000); + }); + + it("120000 (对齐 CC 默认) → 120000", () => { + process.env.FUSION_SUBAGENT_AUTO_BACKGROUND_MS = "120000"; + expect(getSubagentAutoBackgroundMs()).toBe(120000); + }); + + it("0 → 0 (显式 off)", () => { + process.env.FUSION_SUBAGENT_AUTO_BACKGROUND_MS = "0"; + expect(getSubagentAutoBackgroundMs()).toBe(0); + }); + + it("负数 → 0 (fail-off)", () => { + process.env.FUSION_SUBAGENT_AUTO_BACKGROUND_MS = "-5"; + expect(getSubagentAutoBackgroundMs()).toBe(0); + }); + + it("非数 → 0 (fail-off)", () => { + process.env.FUSION_SUBAGENT_AUTO_BACKGROUND_MS = "abc"; + expect(getSubagentAutoBackgroundMs()).toBe(0); + }); + + // 还原 + if (orig === undefined) { + delete process.env.FUSION_SUBAGENT_AUTO_BACKGROUND_MS; + } else { + process.env.FUSION_SUBAGENT_AUTO_BACKGROUND_MS = orig; + } +}); diff --git a/src/tools/AgentTool/AgentTool.tsx b/src/tools/AgentTool/AgentTool.tsx index c965a4b..c40272a 100644 --- a/src/tools/AgentTool/AgentTool.tsx +++ b/src/tools/AgentTool/AgentTool.tsx @@ -121,6 +121,7 @@ import { isForkSubagentEnabled, isInForkChild, } from "./forkSubagent.js"; +import { getSubagentAutoBackgroundMs } from "./autoBackground.js"; import type { AgentDefinition } from "./loadAgentsDir.js"; import { filterAgentsByMcpRequirements, @@ -159,6 +160,14 @@ const isBackgroundTasksDisabled = // Auto-background agent tasks after this many ms (0 = disabled) // Enabled by env var OR GrowthBook gate (checked lazily since GB may not be ready at module load) function getAutoBackgroundMs(): number { + // item 12: FUSION_SUBAGENT_AUTO_BACKGROUND_MS 显式阈值 (并行 item 4 + // FUSION_MCP_AUTO_BACKGROUND_MS)。default 0=off, byte-identical 旧行为。 + // 设正值 → subagent 运行该毫秒后转后台, 复用 registerAgentForeground + // 定时器→backgroundSignal→mid-run 后台化解阻塞 turn。 + const fusionMs = getSubagentAutoBackgroundMs(); + if (fusionMs > 0) { + return fusionMs; + } if ( isEnvTruthy(process.env.CLAUDE_AUTO_BACKGROUND_TASKS) || getFeatureValue_CACHED_MAY_BE_STALE("tengu_auto_background_agents", false) diff --git a/src/tools/AgentTool/autoBackground.ts b/src/tools/AgentTool/autoBackground.ts new file mode 100644 index 0000000..0ed7f82 --- /dev/null +++ b/src/tools/AgentTool/autoBackground.ts @@ -0,0 +1,16 @@ +// item 12 (CC 2.1.198/232): 子代理自动后台化阈值解析。 +// 并行 item 4 FUSION_MCP_AUTO_BACKGROUND_MS (src/services/mcp/client.ts)。 +// FUSION_SUBAGENT_AUTO_BACKGROUND_MS 设正值 → subagent 运行该毫秒后转后台, +// 复用 registerAgentForeground 定时器→backgroundSignal→mid-run 后台化解阻塞 turn。 +// default 0=off, byte-identical 旧行为。 +export function getSubagentAutoBackgroundMs(): number { + const raw = process.env.FUSION_SUBAGENT_AUTO_BACKGROUND_MS; + if (raw === undefined || raw === "") { + return 0; + } + const parsed = parseInt(raw, 10); + if (!Number.isFinite(parsed) || parsed <= 0) { + return 0; + } + return parsed; +}