mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-11 13:21:41 +00:00
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:
@@ -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)),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user