mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-22 06:32:00 +00:00
183 lines
5.4 KiB
TypeScript
183 lines
5.4 KiB
TypeScript
import { SUBAGENT_ENDED_REASON_KILLED } from "./subagent-lifecycle-events.js";
|
|
import { subagentRuns } from "./subagent-registry-memory.js";
|
|
import {
|
|
countActiveDescendantRunsFromRuns,
|
|
listDescendantRunsForRequesterFromRuns,
|
|
listRunsForControllerFromRuns,
|
|
} from "./subagent-registry-queries.js";
|
|
import { getSubagentRunsSnapshotForRead } from "./subagent-registry-state.js";
|
|
import type { SubagentRunRecord } from "./subagent-registry.types.js";
|
|
|
|
function resolveSubagentSessionStartedAt(
|
|
entry: Pick<SubagentRunRecord, "sessionStartedAt" | "startedAt" | "createdAt">,
|
|
): number | undefined {
|
|
if (typeof entry.sessionStartedAt === "number" && Number.isFinite(entry.sessionStartedAt)) {
|
|
return entry.sessionStartedAt;
|
|
}
|
|
if (typeof entry.startedAt === "number" && Number.isFinite(entry.startedAt)) {
|
|
return entry.startedAt;
|
|
}
|
|
return typeof entry.createdAt === "number" && Number.isFinite(entry.createdAt)
|
|
? entry.createdAt
|
|
: undefined;
|
|
}
|
|
|
|
export function getSubagentSessionStartedAt(
|
|
entry: Pick<SubagentRunRecord, "sessionStartedAt" | "startedAt" | "createdAt"> | null | undefined,
|
|
): number | undefined {
|
|
return entry ? resolveSubagentSessionStartedAt(entry) : undefined;
|
|
}
|
|
|
|
export function getSubagentSessionRuntimeMs(
|
|
entry:
|
|
| Pick<SubagentRunRecord, "startedAt" | "endedAt" | "accumulatedRuntimeMs">
|
|
| null
|
|
| undefined,
|
|
now = Date.now(),
|
|
): number | undefined {
|
|
if (!entry) {
|
|
return undefined;
|
|
}
|
|
|
|
const accumulatedRuntimeMs =
|
|
typeof entry.accumulatedRuntimeMs === "number" && Number.isFinite(entry.accumulatedRuntimeMs)
|
|
? Math.max(0, entry.accumulatedRuntimeMs)
|
|
: 0;
|
|
|
|
if (typeof entry.startedAt !== "number" || !Number.isFinite(entry.startedAt)) {
|
|
return entry.accumulatedRuntimeMs != null ? accumulatedRuntimeMs : undefined;
|
|
}
|
|
|
|
const currentRunEndedAt =
|
|
typeof entry.endedAt === "number" && Number.isFinite(entry.endedAt) ? entry.endedAt : now;
|
|
return Math.max(0, accumulatedRuntimeMs + Math.max(0, currentRunEndedAt - entry.startedAt));
|
|
}
|
|
|
|
export function resolveSubagentSessionStatus(
|
|
entry: Pick<SubagentRunRecord, "endedAt" | "endedReason" | "outcome"> | null | undefined,
|
|
): "running" | "killed" | "failed" | "timeout" | "done" | undefined {
|
|
if (!entry) {
|
|
return undefined;
|
|
}
|
|
if (!entry.endedAt) {
|
|
return "running";
|
|
}
|
|
if (entry.endedReason === SUBAGENT_ENDED_REASON_KILLED) {
|
|
return "killed";
|
|
}
|
|
const status = entry.outcome?.status;
|
|
if (status === "error") {
|
|
return "failed";
|
|
}
|
|
if (status === "timeout") {
|
|
return "timeout";
|
|
}
|
|
return "done";
|
|
}
|
|
|
|
export function listSubagentRunsForController(controllerSessionKey: string): SubagentRunRecord[] {
|
|
return listRunsForControllerFromRuns(
|
|
getSubagentRunsSnapshotForRead(subagentRuns),
|
|
controllerSessionKey,
|
|
);
|
|
}
|
|
|
|
export function countActiveDescendantRuns(rootSessionKey: string): number {
|
|
return countActiveDescendantRunsFromRuns(
|
|
getSubagentRunsSnapshotForRead(subagentRuns),
|
|
rootSessionKey,
|
|
);
|
|
}
|
|
|
|
export function listDescendantRunsForRequester(rootSessionKey: string): SubagentRunRecord[] {
|
|
return listDescendantRunsForRequesterFromRuns(
|
|
getSubagentRunsSnapshotForRead(subagentRuns),
|
|
rootSessionKey,
|
|
);
|
|
}
|
|
|
|
export function getSubagentRunByChildSessionKey(childSessionKey: string): SubagentRunRecord | null {
|
|
const key = childSessionKey.trim();
|
|
if (!key) {
|
|
return null;
|
|
}
|
|
|
|
let latestActive: SubagentRunRecord | null = null;
|
|
let latestEnded: SubagentRunRecord | null = null;
|
|
for (const entry of getSubagentRunsSnapshotForRead(subagentRuns).values()) {
|
|
if (entry.childSessionKey !== key) {
|
|
continue;
|
|
}
|
|
if (typeof entry.endedAt !== "number") {
|
|
if (!latestActive || entry.createdAt > latestActive.createdAt) {
|
|
latestActive = entry;
|
|
}
|
|
continue;
|
|
}
|
|
if (!latestEnded || entry.createdAt > latestEnded.createdAt) {
|
|
latestEnded = entry;
|
|
}
|
|
}
|
|
|
|
return latestActive ?? latestEnded;
|
|
}
|
|
|
|
export function getSessionDisplaySubagentRunByChildSessionKey(
|
|
childSessionKey: string,
|
|
): SubagentRunRecord | null {
|
|
const key = childSessionKey.trim();
|
|
if (!key) {
|
|
return null;
|
|
}
|
|
|
|
let latestInMemoryActive: SubagentRunRecord | null = null;
|
|
let latestInMemoryEnded: SubagentRunRecord | null = null;
|
|
for (const entry of subagentRuns.values()) {
|
|
if (entry.childSessionKey !== key) {
|
|
continue;
|
|
}
|
|
if (typeof entry.endedAt === "number") {
|
|
if (!latestInMemoryEnded || entry.createdAt > latestInMemoryEnded.createdAt) {
|
|
latestInMemoryEnded = entry;
|
|
}
|
|
continue;
|
|
}
|
|
if (!latestInMemoryActive || entry.createdAt > latestInMemoryActive.createdAt) {
|
|
latestInMemoryActive = entry;
|
|
}
|
|
}
|
|
|
|
if (latestInMemoryEnded || latestInMemoryActive) {
|
|
if (
|
|
latestInMemoryEnded &&
|
|
(!latestInMemoryActive || latestInMemoryEnded.createdAt > latestInMemoryActive.createdAt)
|
|
) {
|
|
return latestInMemoryEnded;
|
|
}
|
|
return latestInMemoryActive ?? latestInMemoryEnded;
|
|
}
|
|
|
|
return getSubagentRunByChildSessionKey(key);
|
|
}
|
|
|
|
export function getLatestSubagentRunByChildSessionKey(
|
|
childSessionKey: string,
|
|
): SubagentRunRecord | null {
|
|
const key = childSessionKey.trim();
|
|
if (!key) {
|
|
return null;
|
|
}
|
|
|
|
let latest: SubagentRunRecord | null = null;
|
|
for (const entry of getSubagentRunsSnapshotForRead(subagentRuns).values()) {
|
|
if (entry.childSessionKey !== key) {
|
|
continue;
|
|
}
|
|
if (!latest || entry.createdAt > latest.createdAt) {
|
|
latest = entry;
|
|
}
|
|
}
|
|
|
|
return latest;
|
|
}
|