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

@@ -31,6 +31,7 @@ import { optionalStringEnum } from "../schema/typebox.js";
import { getSubagentDepthFromSessionStore } from "../subagent-depth.js";
import {
clearSubagentRunSteerRestart,
countPendingDescendantRuns,
listSubagentRunsForRequester,
markSubagentRunTerminated,
markSubagentRunForSteerRestart,
@@ -70,7 +71,10 @@ type ResolvedRequesterKey = {
callerIsSubagent: boolean;
};
function resolveRunStatus(entry: SubagentRunRecord) {
function resolveRunStatus(entry: SubagentRunRecord, options?: { hasPendingDescendants?: boolean }) {
if (options?.hasPendingDescendants) {
return "active";
}
if (!entry.endedAt) {
return "running";
}
@@ -365,6 +369,16 @@ export function createSubagentsTool(opts?: { agentSessionKey?: string }): AnyAge
const recentCutoff = now - recentMinutes * 60_000;
const cache = new Map<string, Record<string, SessionEntry>>();
const pendingDescendantCache = new Map<string, boolean>();
const hasPendingDescendants = (sessionKey: string) => {
if (pendingDescendantCache.has(sessionKey)) {
return pendingDescendantCache.get(sessionKey) === true;
}
const hasPending = countPendingDescendantRuns(sessionKey) > 0;
pendingDescendantCache.set(sessionKey, hasPending);
return hasPending;
};
let index = 1;
const buildListEntry = (entry: SubagentRunRecord, runtimeMs: number) => {
const sessionEntry = resolveSessionEntryForKey({
@@ -374,7 +388,9 @@ export function createSubagentsTool(opts?: { agentSessionKey?: string }): AnyAge
}).entry;
const totalTokens = resolveTotalTokens(sessionEntry);
const usageText = formatTokenUsageDisplay(sessionEntry);
const status = resolveRunStatus(entry);
const status = resolveRunStatus(entry, {
hasPendingDescendants: hasPendingDescendants(entry.childSessionKey),
});
const runtime = formatDurationCompact(runtimeMs);
const label = truncateLine(resolveSubagentLabel(entry), 48);
const task = truncateLine(entry.task.trim(), 72);
@@ -396,10 +412,15 @@ export function createSubagentsTool(opts?: { agentSessionKey?: string }): AnyAge
return { line, view: entry.endedAt ? { ...baseView, endedAt: entry.endedAt } : baseView };
};
const active = runs
.filter((entry) => !entry.endedAt)
.filter((entry) => !entry.endedAt || hasPendingDescendants(entry.childSessionKey))
.map((entry) => buildListEntry(entry, now - (entry.startedAt ?? entry.createdAt)));
const recent = runs
.filter((entry) => !!entry.endedAt && (entry.endedAt ?? 0) >= recentCutoff)
.filter(
(entry) =>
!!entry.endedAt &&
!hasPendingDescendants(entry.childSessionKey) &&
(entry.endedAt ?? 0) >= recentCutoff,
)
.map((entry) =>
buildListEntry(entry, (entry.endedAt ?? now) - (entry.startedAt ?? entry.createdAt)),
);