fix: agent-only announce path, BB message IDs, sender identity, SSRF allowlist (#23970)

* fix(agents): defer announces until descendant cleanup settles

* fix(bluebubbles): harden message metadata extraction

* feat(contributors): rank by composite score (commits, PRs, LOC, tenure)

* refactor(control-ui): move method guard after path checks to improve request handling

* fix subagent completion announce when only current run is pending

* fix(subagents): keep orchestrator runs active until descendants finish

* fix: prepare PR feedback follow-ups (#23970) (thanks @tyler6204)
This commit is contained in:
Tyler Yust
2026-03-01 22:52:11 -08:00
committed by GitHub
parent cfba64c9db
commit f918b336d1
22 changed files with 814 additions and 155 deletions

View File

@@ -876,6 +876,59 @@ describe("sessions tools", () => {
expect(details.text).toContain("recent (last 30m):");
});
it("subagents list keeps ended orchestrators active while descendants are pending", async () => {
resetSubagentRegistryForTests();
const now = Date.now();
addSubagentRunForTests({
runId: "run-orchestrator-ended",
childSessionKey: "agent:main:subagent:orchestrator-ended",
requesterSessionKey: "agent:main:main",
requesterDisplayKey: "main",
task: "orchestrate child workers",
cleanup: "keep",
createdAt: now - 5 * 60_000,
startedAt: now - 5 * 60_000,
endedAt: now - 4 * 60_000,
outcome: { status: "ok" },
});
addSubagentRunForTests({
runId: "run-orchestrator-child-active",
childSessionKey: "agent:main:subagent:orchestrator-ended:subagent:child",
requesterSessionKey: "agent:main:subagent:orchestrator-ended",
requesterDisplayKey: "subagent:orchestrator-ended",
task: "child worker still running",
cleanup: "keep",
createdAt: now - 60_000,
startedAt: now - 60_000,
});
const tool = createOpenClawTools({
agentSessionKey: "agent:main:main",
}).find((candidate) => candidate.name === "subagents");
expect(tool).toBeDefined();
if (!tool) {
throw new Error("missing subagents tool");
}
const result = await tool.execute("call-subagents-list-orchestrator", { action: "list" });
const details = result.details as {
status?: string;
active?: Array<{ runId?: string; status?: string }>;
recent?: Array<{ runId?: string }>;
};
expect(details.status).toBe("ok");
expect(details.active).toEqual(
expect.arrayContaining([
expect.objectContaining({
runId: "run-orchestrator-ended",
status: "active",
}),
]),
);
expect(details.recent?.find((entry) => entry.runId === "run-orchestrator-ended")).toBeFalsy();
});
it("subagents list usage separates io tokens from prompt/cache", async () => {
resetSubagentRegistryForTests();
const now = Date.now();