@amd-gaia/agent-ui 0.21.2 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/gaia-ui.cjs +1 -1
- package/dist/assets/{browser-B1LxEoD3.js → browser-C-_jUAU-.js} +3 -3
- package/dist/assets/index-C4_mR67p.js +69 -0
- package/dist/assets/index-ChKtY1lF.css +1 -0
- package/dist/index.html +2 -2
- package/main-safety-net.cjs +13 -3
- package/main.cjs +201 -2
- package/package.json +5 -5
- package/preload.cjs +10 -1
- package/services/agent-process-manager.cjs +287 -6
- package/services/agent-seeder.cjs +256 -14
- package/services/auto-updater.cjs +132 -17
- package/services/backend-installer-progress-dialog.cjs +1 -1
- package/services/backend-installer.cjs +151 -69
- package/services/deep-link.cjs +230 -0
- package/services/system-metrics.cjs +154 -0
- package/dist/assets/index-BaBSHxtq.js +0 -72
- package/dist/assets/index-CGT9a3El.css +0 -1
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* GAIA Agent UI — System metrics collection (issue #2007)
|
|
6
|
+
*
|
|
7
|
+
* Collects real host metrics (CPU, memory, disk, network, per-process
|
|
8
|
+
* usage) for the observability dashboard and exposes them to the
|
|
9
|
+
* renderer over the `system:get-metrics` IPC channel. The shape matches
|
|
10
|
+
* the renderer's `SystemMetrics` type (src/types/agent.ts).
|
|
11
|
+
*
|
|
12
|
+
* GPU/NPU utilization is intentionally omitted (left `undefined`): there
|
|
13
|
+
* is no dependency-free cross-platform source for it, and the renderer
|
|
14
|
+
* type marks those fields optional — `undefined` renders as
|
|
15
|
+
* "unavailable", never as a fake zero.
|
|
16
|
+
*
|
|
17
|
+
* Errors propagate: a failing source rejects the IPC invoke so the
|
|
18
|
+
* renderer can surface it. No silent nulls.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
"use strict";
|
|
22
|
+
|
|
23
|
+
const fs = require("fs");
|
|
24
|
+
const os = require("os");
|
|
25
|
+
const { app, ipcMain } = require("electron");
|
|
26
|
+
|
|
27
|
+
const SYSTEM_GET_METRICS_CHANNEL = "system:get-metrics";
|
|
28
|
+
|
|
29
|
+
const BYTES_PER_GB = 1024 * 1024 * 1024;
|
|
30
|
+
|
|
31
|
+
/** Minimum sampling window for the very first CPU reading (ms). */
|
|
32
|
+
const FIRST_CPU_SAMPLE_MS = 120;
|
|
33
|
+
|
|
34
|
+
// Previous aggregate CPU times — CPU% is a delta between two samples.
|
|
35
|
+
let prevCpuTimes = null;
|
|
36
|
+
|
|
37
|
+
function readCpuTimes() {
|
|
38
|
+
let idle = 0;
|
|
39
|
+
let total = 0;
|
|
40
|
+
for (const cpu of os.cpus()) {
|
|
41
|
+
for (const [kind, ms] of Object.entries(cpu.times)) {
|
|
42
|
+
total += ms;
|
|
43
|
+
if (kind === "idle") idle += ms;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return { idle, total };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function cpuPercentBetween(prev, curr) {
|
|
50
|
+
const totalDelta = curr.total - prev.total;
|
|
51
|
+
const idleDelta = curr.idle - prev.idle;
|
|
52
|
+
if (totalDelta <= 0) return 0;
|
|
53
|
+
const pct = (1 - idleDelta / totalDelta) * 100;
|
|
54
|
+
return Math.min(100, Math.max(0, pct));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function sampleCpuPercent() {
|
|
58
|
+
if (prevCpuTimes === null) {
|
|
59
|
+
// First call: take a short two-point sample so the reading is real,
|
|
60
|
+
// not a since-boot average.
|
|
61
|
+
prevCpuTimes = readCpuTimes();
|
|
62
|
+
await new Promise((r) => setTimeout(r, FIRST_CPU_SAMPLE_MS));
|
|
63
|
+
}
|
|
64
|
+
const curr = readCpuTimes();
|
|
65
|
+
const pct = cpuPercentBetween(prevCpuTimes, curr);
|
|
66
|
+
prevCpuTimes = curr;
|
|
67
|
+
return pct;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function readDiskUsage(diskPath) {
|
|
71
|
+
let stat;
|
|
72
|
+
try {
|
|
73
|
+
stat = await fs.promises.statfs(diskPath);
|
|
74
|
+
} catch (err) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`Failed to read disk usage for ${diskPath}: ${err.message}. ` +
|
|
77
|
+
"The observability dashboard needs a readable filesystem path — " +
|
|
78
|
+
"check that the path exists and is accessible."
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
const totalBytes = stat.blocks * stat.bsize;
|
|
82
|
+
const freeBytes = stat.bfree * stat.bsize;
|
|
83
|
+
return {
|
|
84
|
+
diskUsedGB: (totalBytes - freeBytes) / BYTES_PER_GB,
|
|
85
|
+
diskTotalGB: totalBytes / BYTES_PER_GB,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function readProcesses(now) {
|
|
90
|
+
// Electron's own process tree (main, renderer, GPU, utility) — the
|
|
91
|
+
// processes this app can meaningfully report on without a system-wide
|
|
92
|
+
// process scanner dependency.
|
|
93
|
+
return app.getAppMetrics().map((p) => ({
|
|
94
|
+
pid: p.pid,
|
|
95
|
+
name: p.name || p.serviceName || p.type,
|
|
96
|
+
cpuPercent: p.cpu.percentCPUUsage,
|
|
97
|
+
memoryMB: p.memory.workingSetSize / 1024, // workingSetSize is in KB
|
|
98
|
+
uptime: p.creationTime ? Math.max(0, (now - p.creationTime) / 1000) : 0,
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function readNetworkUp() {
|
|
103
|
+
return Object.values(os.networkInterfaces()).some((addrs) =>
|
|
104
|
+
(addrs || []).some((a) => !a.internal)
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Collect a full SystemMetrics snapshot from the real host.
|
|
110
|
+
*
|
|
111
|
+
* @param {object} [options]
|
|
112
|
+
* @param {string} [options.diskPath] Filesystem path to report disk usage
|
|
113
|
+
* for (defaults to the user's home directory).
|
|
114
|
+
* @returns {Promise<object>} SystemMetrics-shaped snapshot.
|
|
115
|
+
*/
|
|
116
|
+
async function collectSystemMetrics(options = {}) {
|
|
117
|
+
const diskPath = options.diskPath || os.homedir();
|
|
118
|
+
|
|
119
|
+
const [cpuPercent, disk] = await Promise.all([
|
|
120
|
+
sampleCpuPercent(),
|
|
121
|
+
readDiskUsage(diskPath),
|
|
122
|
+
]);
|
|
123
|
+
|
|
124
|
+
const totalMem = os.totalmem();
|
|
125
|
+
const freeMem = os.freemem();
|
|
126
|
+
const now = Date.now();
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
cpuPercent,
|
|
130
|
+
memoryUsedGB: (totalMem - freeMem) / BYTES_PER_GB,
|
|
131
|
+
memoryTotalGB: totalMem / BYTES_PER_GB,
|
|
132
|
+
diskUsedGB: disk.diskUsedGB,
|
|
133
|
+
diskTotalGB: disk.diskTotalGB,
|
|
134
|
+
networkUp: readNetworkUp(),
|
|
135
|
+
processes: readProcesses(now),
|
|
136
|
+
timestamp: now,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Register the `system:get-metrics` IPC handler. Collection errors reject
|
|
142
|
+
* the renderer's invoke() so the store can surface them.
|
|
143
|
+
*/
|
|
144
|
+
function registerIpcHandlers() {
|
|
145
|
+
ipcMain.handle(SYSTEM_GET_METRICS_CHANNEL, async () => {
|
|
146
|
+
return collectSystemMetrics();
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
module.exports = {
|
|
151
|
+
collectSystemMetrics,
|
|
152
|
+
registerIpcHandlers,
|
|
153
|
+
SYSTEM_GET_METRICS_CHANNEL,
|
|
154
|
+
};
|