mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-27 01:41:40 +00:00
fix: dedupe active child session counts
This commit is contained in:
@@ -227,6 +227,62 @@ describe("sessions_spawn depth + child limits", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("does not double-count restarted child sessions toward maxChildrenPerAgent", async () => {
|
||||
configOverride = {
|
||||
session: createPerSenderSessionConfig({ store: storeTemplatePath }),
|
||||
agents: {
|
||||
defaults: {
|
||||
subagents: {
|
||||
maxSpawnDepth: 2,
|
||||
maxChildrenPerAgent: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const childSessionKey = "agent:main:subagent:restarted-child";
|
||||
addSubagentRunForTests({
|
||||
runId: "existing-old-run",
|
||||
childSessionKey,
|
||||
requesterSessionKey: "agent:main:subagent:parent",
|
||||
requesterDisplayKey: "agent:main:subagent:parent",
|
||||
task: "old orchestration run",
|
||||
cleanup: "keep",
|
||||
createdAt: Date.now() - 30_000,
|
||||
startedAt: Date.now() - 30_000,
|
||||
endedAt: Date.now() - 20_000,
|
||||
cleanupCompletedAt: undefined,
|
||||
});
|
||||
addSubagentRunForTests({
|
||||
runId: "existing-current-run",
|
||||
childSessionKey,
|
||||
requesterSessionKey: "agent:main:subagent:parent",
|
||||
requesterDisplayKey: "agent:main:subagent:parent",
|
||||
task: "current orchestration run",
|
||||
cleanup: "keep",
|
||||
createdAt: Date.now() - 10_000,
|
||||
startedAt: Date.now() - 10_000,
|
||||
});
|
||||
addSubagentRunForTests({
|
||||
runId: "existing-descendant-run",
|
||||
childSessionKey: `${childSessionKey}:subagent:leaf`,
|
||||
requesterSessionKey: childSessionKey,
|
||||
requesterDisplayKey: childSessionKey,
|
||||
task: "descendant still running",
|
||||
cleanup: "keep",
|
||||
createdAt: Date.now() - 5_000,
|
||||
startedAt: Date.now() - 5_000,
|
||||
});
|
||||
|
||||
const tool = createSessionsSpawnTool({ agentSessionKey: "agent:main:subagent:parent" });
|
||||
const result = await tool.execute("call-max-children-dedupe", { task: "hello" });
|
||||
|
||||
expect(result.details).toMatchObject({
|
||||
status: "accepted",
|
||||
runId: "run-depth",
|
||||
});
|
||||
});
|
||||
|
||||
it("does not use subagent maxConcurrent as a per-parent spawn gate", async () => {
|
||||
configOverride = {
|
||||
session: createPerSenderSessionConfig({ store: storeTemplatePath }),
|
||||
|
||||
@@ -175,6 +175,37 @@ describe("subagent registry query regressions", () => {
|
||||
expect(countActiveRunsForSessionFromRuns(runs, "agent:main:main")).toBe(0);
|
||||
});
|
||||
|
||||
it("dedupes stale and current rows for the same child session when counting active runs", () => {
|
||||
const childSessionKey = "agent:main:subagent:orch-restarted";
|
||||
const runs = toRunMap([
|
||||
makeRun({
|
||||
runId: "run-old",
|
||||
childSessionKey,
|
||||
requesterSessionKey: "agent:main:main",
|
||||
createdAt: 100,
|
||||
startedAt: 100,
|
||||
endedAt: 150,
|
||||
cleanupCompletedAt: undefined,
|
||||
}),
|
||||
makeRun({
|
||||
runId: "run-current",
|
||||
childSessionKey,
|
||||
requesterSessionKey: "agent:main:main",
|
||||
createdAt: 200,
|
||||
startedAt: 200,
|
||||
}),
|
||||
makeRun({
|
||||
runId: "run-descendant-active",
|
||||
childSessionKey: `${childSessionKey}:subagent:child`,
|
||||
requesterSessionKey: childSessionKey,
|
||||
createdAt: 210,
|
||||
startedAt: 210,
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(countActiveRunsForSessionFromRuns(runs, "agent:main:main")).toBe(1);
|
||||
});
|
||||
|
||||
it("scopes direct child listings to the requester run window when requesterRunId is provided", () => {
|
||||
const requesterSessionKey = "agent:main:subagent:orchestrator";
|
||||
const runs = toRunMap([
|
||||
|
||||
@@ -136,11 +136,19 @@ export function countActiveRunsForSessionFromRuns(
|
||||
return pending;
|
||||
};
|
||||
|
||||
let count = 0;
|
||||
const latestByChildSessionKey = new Map<string, SubagentRunRecord>();
|
||||
for (const entry of runs.values()) {
|
||||
if (resolveControllerSessionKey(entry) !== key) {
|
||||
continue;
|
||||
}
|
||||
const existing = latestByChildSessionKey.get(entry.childSessionKey);
|
||||
if (!existing || entry.createdAt > existing.createdAt) {
|
||||
latestByChildSessionKey.set(entry.childSessionKey, entry);
|
||||
}
|
||||
}
|
||||
|
||||
let count = 0;
|
||||
for (const entry of latestByChildSessionKey.values()) {
|
||||
if (typeof entry.endedAt !== "number") {
|
||||
count += 1;
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user