mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-20 13:13:06 +00:00
refactor: dedupe subagent session metrics
This commit is contained in:
@@ -10,12 +10,20 @@ import {
|
||||
} from "../config/sessions.js";
|
||||
import { defaultRuntime } from "../runtime.js";
|
||||
import { type SubagentRunOutcome } from "./subagent-announce.js";
|
||||
import {
|
||||
SUBAGENT_ENDED_REASON_ERROR,
|
||||
SUBAGENT_ENDED_REASON_KILLED,
|
||||
} from "./subagent-lifecycle-events.js";
|
||||
import { SUBAGENT_ENDED_REASON_ERROR } from "./subagent-lifecycle-events.js";
|
||||
import { runOutcomesEqual } from "./subagent-registry-completion.js";
|
||||
import type { SubagentRunRecord } from "./subagent-registry.types.js";
|
||||
import {
|
||||
getSubagentSessionRuntimeMs,
|
||||
getSubagentSessionStartedAt,
|
||||
resolveSubagentSessionStatus,
|
||||
} from "./subagent-session-metrics.js";
|
||||
|
||||
export {
|
||||
getSubagentSessionRuntimeMs,
|
||||
getSubagentSessionStartedAt,
|
||||
resolveSubagentSessionStatus,
|
||||
} from "./subagent-session-metrics.js";
|
||||
|
||||
export const MIN_ANNOUNCE_RETRY_DELAY_MS = 1_000;
|
||||
export const MAX_ANNOUNCE_RETRY_DELAY_MS = 8_000;
|
||||
@@ -77,73 +85,6 @@ function findSessionEntryByKey(store: Record<string, SessionEntry>, sessionKey:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function resolveSubagentSessionStatus(
|
||||
entry: Pick<SubagentRunRecord, "endedAt" | "endedReason" | "outcome"> | null | undefined,
|
||||
): SessionEntry["status"] {
|
||||
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";
|
||||
}
|
||||
|
||||
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 async function persistSubagentSessionTiming(entry: SubagentRunRecord) {
|
||||
const childSessionKey = entry.childSessionKey?.trim();
|
||||
if (!childSessionKey) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { SUBAGENT_ENDED_REASON_KILLED } from "./subagent-lifecycle-events.js";
|
||||
import { subagentRuns } from "./subagent-registry-memory.js";
|
||||
import {
|
||||
countActiveDescendantRunsFromRuns,
|
||||
@@ -7,73 +6,17 @@ import {
|
||||
} from "./subagent-registry-queries.js";
|
||||
import { getSubagentRunsSnapshotForRead } from "./subagent-registry-state.js";
|
||||
import type { SubagentRunRecord } from "./subagent-registry.types.js";
|
||||
import {
|
||||
getSubagentSessionRuntimeMs,
|
||||
getSubagentSessionStartedAt,
|
||||
resolveSubagentSessionStatus,
|
||||
} from "./subagent-session-metrics.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 {
|
||||
getSubagentSessionRuntimeMs,
|
||||
getSubagentSessionStartedAt,
|
||||
resolveSubagentSessionStatus,
|
||||
} from "./subagent-session-metrics.js";
|
||||
|
||||
export function listSubagentRunsForController(controllerSessionKey: string): SubagentRunRecord[] {
|
||||
return listRunsForControllerFromRuns(
|
||||
|
||||
69
src/agents/subagent-session-metrics.ts
Normal file
69
src/agents/subagent-session-metrics.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { SUBAGENT_ENDED_REASON_KILLED } from "./subagent-lifecycle-events.js";
|
||||
import type { SubagentRunRecord } from "./subagent-registry.types.js";
|
||||
|
||||
function resolveSubagentSessionStartedAtInternal(
|
||||
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 ? resolveSubagentSessionStartedAtInternal(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";
|
||||
}
|
||||
Reference in New Issue
Block a user