98 lines
3.6 KiB
JavaScript
98 lines
3.6 KiB
JavaScript
function trimText(value, maxLength = 160) {
|
|
const text = typeof value === "string" ? value.trim() : "";
|
|
if (!text) {
|
|
return undefined;
|
|
}
|
|
return text.length > maxLength ? `${text.slice(0, maxLength)}...` : text;
|
|
}
|
|
|
|
function summarizePoll(poll) {
|
|
if (!poll || typeof poll !== "object") {
|
|
return null;
|
|
}
|
|
return {
|
|
at: trimText(poll.at, 80),
|
|
ok: poll.ok === true,
|
|
status: Number.isFinite(Number(poll.status)) ? Number(poll.status) : undefined,
|
|
};
|
|
}
|
|
|
|
function summarizeActiveMasterTask(activeMasterTask) {
|
|
if (!activeMasterTask || typeof activeMasterTask !== "object") {
|
|
return null;
|
|
}
|
|
return {
|
|
taskId: trimText(activeMasterTask.taskId, 80),
|
|
status: trimText(activeMasterTask.status, 80),
|
|
startedAt: trimText(activeMasterTask.startedAt, 80),
|
|
completedAt: trimText(activeMasterTask.completedAt, 80),
|
|
};
|
|
}
|
|
|
|
function summarizeReliableOutbox(runtime) {
|
|
const replay = runtime?.lastReliableOutboxReplay;
|
|
return {
|
|
busy: runtime?.reliableOutboxReplayBusy === true,
|
|
startedAt: trimText(runtime?.lastReliableOutboxReplayStartedAt, 80),
|
|
replayedAt: trimText(runtime?.lastReliableOutboxReplayAt, 80),
|
|
attempted: Number.isFinite(Number(replay?.attempted)) ? Number(replay.attempted) : 0,
|
|
sent: Number.isFinite(Number(replay?.sent)) ? Number(replay.sent) : 0,
|
|
retained: Number.isFinite(Number(replay?.retained)) ? Number(replay.retained) : 0,
|
|
stoppedByBudget: replay?.stoppedByBudget === true,
|
|
error: trimText(replay?.error),
|
|
};
|
|
}
|
|
|
|
function summarizeCodexAppServer(runtime) {
|
|
return {
|
|
metadataAtMs: Number.isFinite(Number(runtime?.codexAppServerCapabilityMetadataAtMs))
|
|
? Number(runtime.codexAppServerCapabilityMetadataAtMs)
|
|
: undefined,
|
|
refreshBusy: runtime?.codexAppServerCapabilityMetadataRefreshBusy === true,
|
|
lastError: trimText(runtime?.codexAppServerCapabilityMetadataError),
|
|
skippedAt: trimText(runtime?.codexAppServerCapabilityMetadataSkippedAt, 80),
|
|
skipReason: trimText(runtime?.codexAppServerCapabilityMetadataSkipReason, 120),
|
|
};
|
|
}
|
|
|
|
export function buildLocalAgentHealthSummary(config = {}, runtime = {}) {
|
|
return {
|
|
ok: runtime.lastHeartbeatOk === true,
|
|
service: "boss-local-agent",
|
|
deviceId: trimText(config.deviceId, 120),
|
|
now: new Date().toISOString(),
|
|
heartbeat: {
|
|
at: trimText(runtime.lastHeartbeatAt, 80),
|
|
ok: runtime.lastHeartbeatOk === true,
|
|
status: Number.isFinite(Number(runtime.lastHeartbeatStatus))
|
|
? Number(runtime.lastHeartbeatStatus)
|
|
: undefined,
|
|
},
|
|
masterTask: {
|
|
busy: runtime.masterTaskBusy === true,
|
|
active: summarizeActiveMasterTask(runtime.activeMasterTask),
|
|
lastPoll: summarizePoll(runtime.lastMasterTaskPoll),
|
|
},
|
|
outbox: summarizeReliableOutbox(runtime),
|
|
skills: {
|
|
syncBusy: runtime.skillSyncBusy === true,
|
|
syncAt: trimText(runtime.lastSkillSyncAt, 80),
|
|
syncOk: runtime.lastSkillSyncOk === true,
|
|
syncStatus: Number.isFinite(Number(runtime.lastSkillSyncStatus))
|
|
? Number(runtime.lastSkillSyncStatus)
|
|
: undefined,
|
|
count: Array.isArray(runtime.lastSkills) ? runtime.lastSkills.length : 0,
|
|
lifecycleBusy: runtime.skillLifecycleBusy === true,
|
|
lastLifecyclePoll: summarizePoll(runtime.lastSkillLifecyclePoll),
|
|
},
|
|
projectDiscovery: {
|
|
at: trimText(runtime.lastProjectDiscoveryAt, 80),
|
|
ok: runtime.lastProjectDiscoveryOk === true,
|
|
summary: trimText(runtime.lastProjectDiscoverySummary, 160),
|
|
skippedAt: trimText(runtime.lastProjectDiscoverySkippedAt, 80),
|
|
skipReason: trimText(runtime.lastProjectDiscoverySkipReason, 120),
|
|
},
|
|
codexAppServer: summarizeCodexAppServer(runtime),
|
|
};
|
|
}
|