@vtstech/pi-status 1.1.2 → 1.1.4
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/package.json +2 -2
- package/status.js +130 -189
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vtstech/pi-status",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "System monitor / status bar extension for Pi Coding Agent",
|
|
5
5
|
"main": "status.js",
|
|
6
6
|
"keywords": ["pi-extensions"],
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"url": "https://github.com/VTSTech/pi-coding-agent"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@vtstech/pi-shared": "1.1.
|
|
17
|
+
"@vtstech/pi-shared": "1.1.4"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
20
|
"@mariozechner/pi-coding-agent": ">=0.66"
|
package/status.js
CHANGED
|
@@ -1,33 +1,34 @@
|
|
|
1
1
|
// .build-npm/status/status.temp.ts
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import { execSync } from "node:child_process";
|
|
2
4
|
import os from "node:os";
|
|
3
|
-
import { execSync as gitExecSync } from "node:child_process";
|
|
4
5
|
import { getOllamaBaseUrl, fetchModelContextLength, readModelsJson } from "@vtstech/pi-shared/ollama";
|
|
5
6
|
import { fmtBytes, fmtDur } from "@vtstech/pi-shared/format";
|
|
7
|
+
import { debugLog } from "@vtstech/pi-shared/debug";
|
|
8
|
+
var STATUS_UPDATE_INTERVAL_MS = 5e3;
|
|
9
|
+
var TOOL_TIMER_INTERVAL_MS = 1e3;
|
|
6
10
|
function status_temp_default(pi) {
|
|
7
11
|
let lastResponseTime = null;
|
|
8
12
|
let agentStartTime = null;
|
|
9
13
|
let updateInterval = null;
|
|
14
|
+
let toolTimerInterval = null;
|
|
10
15
|
let currentCtx = null;
|
|
11
16
|
let ctxUi = null;
|
|
17
|
+
let ctxTheme = null;
|
|
12
18
|
let prevCpuInfo = getCpuSnapshot();
|
|
13
19
|
let lastPayload = null;
|
|
14
|
-
let tuiRef = null;
|
|
15
|
-
let gitBranchCache = "";
|
|
16
20
|
let cpuUsage = 0;
|
|
17
21
|
let memUsed = 0;
|
|
18
22
|
let memTotal = 0;
|
|
19
23
|
let swapUsed = 0;
|
|
20
24
|
let swapTotal = 0;
|
|
21
25
|
let hasSwap = false;
|
|
22
|
-
let ollamaLoaded = "";
|
|
23
26
|
let footerModel = "";
|
|
24
|
-
let footerThinking = "";
|
|
25
|
-
let footerCtxPct = "";
|
|
26
27
|
let footerNativeCtx = "";
|
|
27
28
|
let nativeCtxModel = "";
|
|
28
29
|
let isLocalProvider = true;
|
|
29
|
-
let
|
|
30
|
-
let
|
|
30
|
+
let versionsText = "";
|
|
31
|
+
let cachedPromptText = null;
|
|
31
32
|
let securityFlashTool = "";
|
|
32
33
|
let securityFlashUntil = 0;
|
|
33
34
|
let activeTool = "";
|
|
@@ -65,18 +66,20 @@ function status_temp_default(pi) {
|
|
|
65
66
|
return { used, total };
|
|
66
67
|
}
|
|
67
68
|
function getSwap() {
|
|
69
|
+
if (process.platform !== "linux") {
|
|
70
|
+
debugLog("status", "swap detection skipped: not a Linux platform");
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
68
73
|
try {
|
|
69
|
-
const out =
|
|
74
|
+
const out = fs.readFileSync("/proc/meminfo", "utf-8");
|
|
70
75
|
const swapTotal2 = Number(out.match(/SwapTotal:\s+(\d+)/)?.[1]) * 1024;
|
|
71
76
|
const swapFree = Number(out.match(/SwapFree:\s+(\d+)/)?.[1]) * 1024;
|
|
72
77
|
if (swapTotal2 > 0) return { used: swapTotal2 - swapFree, total: swapTotal2 };
|
|
73
|
-
} catch {
|
|
78
|
+
} catch (err) {
|
|
79
|
+
debugLog("status", "failed to read /proc/meminfo", err);
|
|
74
80
|
}
|
|
75
81
|
return null;
|
|
76
82
|
}
|
|
77
|
-
let ollamaLoadedCache = "";
|
|
78
|
-
let ollamaLoadedLastCheck = 0;
|
|
79
|
-
const OLLAMA_LOADED_INTERVAL = 15e3;
|
|
80
83
|
function detectLocalProvider(modelsJson) {
|
|
81
84
|
const isLocalUrl = (url) => url.includes("localhost") || url.includes("127.0.0.1") || url.includes("0.0.0.0");
|
|
82
85
|
try {
|
|
@@ -116,68 +119,70 @@ function status_temp_default(pi) {
|
|
|
116
119
|
}
|
|
117
120
|
return footerNativeCtx;
|
|
118
121
|
}
|
|
119
|
-
async function fetchOllamaLoadedModel() {
|
|
120
|
-
try {
|
|
121
|
-
const ollamaBase = getOllamaBaseUrl();
|
|
122
|
-
const res = await fetch(`${ollamaBase}/api/ps`, {
|
|
123
|
-
signal: AbortSignal.timeout(5e3)
|
|
124
|
-
});
|
|
125
|
-
if (!res.ok) return "";
|
|
126
|
-
const data = await res.json();
|
|
127
|
-
const models = data?.models || [];
|
|
128
|
-
if (Array.isArray(models) && models.length > 0) {
|
|
129
|
-
return models[0].name || models[0].model || "";
|
|
130
|
-
}
|
|
131
|
-
} catch {
|
|
132
|
-
}
|
|
133
|
-
return "";
|
|
134
|
-
}
|
|
135
|
-
function getOllamaLoadedModel() {
|
|
136
|
-
const now = Date.now();
|
|
137
|
-
if (now - ollamaLoadedLastCheck < OLLAMA_LOADED_INTERVAL) return ollamaLoadedCache;
|
|
138
|
-
ollamaLoadedLastCheck = now;
|
|
139
|
-
fetchOllamaLoadedModel().then((loaded) => {
|
|
140
|
-
ollamaLoadedCache = loaded;
|
|
141
|
-
}).catch(() => {
|
|
142
|
-
ollamaLoadedCache = "";
|
|
143
|
-
});
|
|
144
|
-
return ollamaLoadedCache;
|
|
145
|
-
}
|
|
146
122
|
function extractParams(payload) {
|
|
147
123
|
const params = [];
|
|
148
124
|
if (payload.temperature !== void 0) params.push(`temp:${payload.temperature}`);
|
|
149
125
|
if (payload.top_p !== void 0) params.push(`top_p:${payload.top_p}`);
|
|
150
126
|
if (payload.top_k !== void 0) params.push(`top_k:${payload.top_k}`);
|
|
151
|
-
if (payload.max_completion_tokens !== void 0) params.push(`max:${payload.max_completion_tokens}`);
|
|
152
|
-
else if (payload.max_tokens !== void 0) params.push(`max:${payload.max_tokens}`);
|
|
153
127
|
if (payload.num_predict !== void 0) params.push(`predict:${payload.num_predict}`);
|
|
154
128
|
if (payload.num_ctx !== void 0) params.push(`ctx:${payload.num_ctx}`);
|
|
155
129
|
if (payload.reasoning_effort !== void 0) params.push(`think:${payload.reasoning_effort}`);
|
|
156
130
|
return params;
|
|
157
131
|
}
|
|
158
|
-
function
|
|
159
|
-
if (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
132
|
+
function flushStatus() {
|
|
133
|
+
if (!ctxUi) return;
|
|
134
|
+
const theme = ctxTheme;
|
|
135
|
+
const dim2 = (s) => theme?.fg?.("dim", s) ?? s;
|
|
136
|
+
const green2 = (s) => theme?.fg?.("success", s) ?? s;
|
|
137
|
+
ctxUi.setStatus("status-cpu", isLocalProvider ? `${dim2("CPU")} ${green2(cpuUsage.toFixed(0) + "%")}` : void 0);
|
|
138
|
+
ctxUi.setStatus("status-ram", isLocalProvider ? `${dim2("RAM")} ${green2(fmtBytes(memUsed) + "/" + fmtBytes(memTotal))}` : void 0);
|
|
139
|
+
ctxUi.setStatus(
|
|
140
|
+
"status-swap",
|
|
141
|
+
isLocalProvider && hasSwap && swapUsed > 0 ? `${dim2("Swap")} ${green2(fmtBytes(swapUsed) + "/" + fmtBytes(swapTotal))}` : void 0
|
|
142
|
+
);
|
|
143
|
+
ctxUi.setStatus(
|
|
144
|
+
"status-native-ctx",
|
|
145
|
+
footerNativeCtx ? `${dim2("CtxMax:")}${green2(footerNativeCtx)}` : void 0
|
|
146
|
+
);
|
|
147
|
+
if (lastPayload) {
|
|
148
|
+
const rawMax = lastPayload.max_completion_tokens ?? lastPayload.max_tokens;
|
|
149
|
+
if (rawMax !== void 0) {
|
|
150
|
+
const formatted = rawMax >= 1e3 ? `${(rawMax / 1e3).toFixed(rawMax % 1e3 === 0 ? 0 : 1)}k` : String(rawMax);
|
|
151
|
+
ctxUi.setStatus("status-resp-max", `${dim2("RespMax:")}${green2(formatted)}`);
|
|
152
|
+
} else {
|
|
153
|
+
ctxUi.setStatus("status-resp-max", void 0);
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
ctxUi.setStatus("status-resp-max", void 0);
|
|
157
|
+
}
|
|
158
|
+
ctxUi.setStatus(
|
|
159
|
+
"status-resp",
|
|
160
|
+
lastResponseTime !== null ? `${dim2("Resp")} ${green2(fmtDur(lastResponseTime))}` : void 0
|
|
161
|
+
);
|
|
162
|
+
if (lastPayload) {
|
|
163
|
+
const params = extractParams(lastPayload);
|
|
164
|
+
ctxUi.setStatus("status-params", params.length > 0 ? dim2(params.join(" ")) : void 0);
|
|
165
|
+
} else {
|
|
166
|
+
ctxUi.setStatus("status-params", void 0);
|
|
167
|
+
}
|
|
168
|
+
const now = Date.now();
|
|
169
|
+
if (securityFlashTool && now < securityFlashUntil) {
|
|
170
|
+
ctxUi.setStatus("status-sec", `${dim2("SEC:")}${green2(String(blockedCount))} ${dim2("(blocked: " + securityFlashTool + ")")}`);
|
|
171
|
+
} else if (blockedCount > 0) {
|
|
172
|
+
ctxUi.setStatus("status-sec", `${dim2("SEC:")}${green2(String(blockedCount))}`);
|
|
173
|
+
} else {
|
|
174
|
+
ctxUi.setStatus("status-sec", void 0);
|
|
175
|
+
}
|
|
176
|
+
if (activeTool && activeToolStart > 0) {
|
|
177
|
+
const elapsed = performance.now() - activeToolStart;
|
|
178
|
+
ctxUi.setStatus("status-tool", `${green2(">")} ${dim2(activeTool + ":")} ${green2(fmtDur(elapsed))}`);
|
|
179
|
+
} else {
|
|
180
|
+
ctxUi.setStatus("status-tool", void 0);
|
|
181
|
+
}
|
|
182
|
+
ctxUi.setStatus("system-prompt", cachedPromptText ?? void 0);
|
|
183
|
+
if (versionsText) {
|
|
184
|
+
ctxUi.setStatus("status-versions", dim2(versionsText));
|
|
176
185
|
}
|
|
177
|
-
return gitBranchCache;
|
|
178
|
-
}
|
|
179
|
-
function incrementBlockedCount() {
|
|
180
|
-
blockedCount++;
|
|
181
186
|
}
|
|
182
187
|
function updateMetrics() {
|
|
183
188
|
cpuUsage = getCpuUsage();
|
|
@@ -192,154 +197,79 @@ function status_temp_default(pi) {
|
|
|
192
197
|
} else {
|
|
193
198
|
hasSwap = false;
|
|
194
199
|
}
|
|
195
|
-
ollamaLoaded = getOllamaLoadedModel();
|
|
196
200
|
const modelsJson = readModelsJson();
|
|
197
201
|
isLocalProvider = modelsJson ? detectLocalProvider(modelsJson) : false;
|
|
198
202
|
if (currentCtx) {
|
|
199
203
|
footerModel = currentCtx.model?.id || "";
|
|
200
|
-
footerThinking = pi.getThinkingLevel?.() ?? "";
|
|
201
|
-
const usage = currentCtx.getContextUsage?.();
|
|
202
|
-
if (usage && usage.contextWindow > 0) {
|
|
203
|
-
const pctVal = (usage.tokens / usage.contextWindow * 100).toFixed(1);
|
|
204
|
-
footerCtxPct = `${pctVal}%/${(usage.contextWindow / 1e3).toFixed(0)}k`;
|
|
205
|
-
} else {
|
|
206
|
-
footerCtxPct = "";
|
|
207
|
-
}
|
|
208
204
|
const modelId = currentCtx.model?.id || "";
|
|
209
|
-
if (modelId
|
|
205
|
+
if (modelId) {
|
|
210
206
|
getNativeModelCtx(modelId);
|
|
211
207
|
}
|
|
212
208
|
}
|
|
209
|
+
flushStatus();
|
|
213
210
|
}
|
|
214
211
|
pi.on("session_start", async (_event, ctx) => {
|
|
215
212
|
currentCtx = ctx;
|
|
216
213
|
ctxUi = ctx.ui;
|
|
214
|
+
ctxTheme = ctx.ui.theme;
|
|
217
215
|
prevCpuInfo = getCpuSnapshot();
|
|
216
|
+
try {
|
|
217
|
+
const out = execSync("pi -v 2>&1", { encoding: "utf-8", timeout: 5e3 }).trim();
|
|
218
|
+
if (out) versionsText = `pi:${out}`;
|
|
219
|
+
} catch {
|
|
220
|
+
}
|
|
218
221
|
updateMetrics();
|
|
219
|
-
ctx.ui.setFooter((tui, theme, footerData) => {
|
|
220
|
-
tuiRef = tui;
|
|
221
|
-
const dim = (s) => theme?.fg?.("dim", s) ?? s;
|
|
222
|
-
const red = (s) => theme?.fg?.("error", s) ?? s;
|
|
223
|
-
const yellow = (s) => theme?.fg?.("yellow", s) ?? s;
|
|
224
|
-
const sep = dim(" \xB7 ");
|
|
225
|
-
const truncateLine = (line, maxW) => {
|
|
226
|
-
const ellipsis = dim("...");
|
|
227
|
-
const visible = line.replace(/\x1b\[[0-9;]*m/g, "");
|
|
228
|
-
if (visible.length > maxW) {
|
|
229
|
-
let vis = 0, cut = 0;
|
|
230
|
-
for (let i = 0; i < line.length && vis < maxW - 3; i++) {
|
|
231
|
-
if (line[i] === "\x1B") {
|
|
232
|
-
while (i < line.length && line[i] !== "m") i++;
|
|
233
|
-
} else {
|
|
234
|
-
vis++;
|
|
235
|
-
}
|
|
236
|
-
cut = i + 1;
|
|
237
|
-
}
|
|
238
|
-
return line.slice(0, cut) + ellipsis;
|
|
239
|
-
}
|
|
240
|
-
return line;
|
|
241
|
-
};
|
|
242
|
-
return {
|
|
243
|
-
render(width) {
|
|
244
|
-
const lines = [];
|
|
245
|
-
let branch = "";
|
|
246
|
-
try {
|
|
247
|
-
branch = footerData?.getGitBranch?.() || "";
|
|
248
|
-
} catch {
|
|
249
|
-
}
|
|
250
|
-
if (!branch) branch = getGitBranch();
|
|
251
|
-
const line1Parts = [];
|
|
252
|
-
if (footerModel) line1Parts.push(`conf:${footerModel}`);
|
|
253
|
-
line1Parts.push(getPwd());
|
|
254
|
-
if (footerThinking && footerThinking !== "off") line1Parts.push(dim(footerThinking));
|
|
255
|
-
if (isLocalProvider) {
|
|
256
|
-
line1Parts.push(dim(`CPU ${cpuUsage.toFixed(0)}%`));
|
|
257
|
-
}
|
|
258
|
-
let line1 = truncateLine(line1Parts.join(sep), width);
|
|
259
|
-
lines.push(line1);
|
|
260
|
-
const line2Parts = [];
|
|
261
|
-
if (ollamaLoaded) line2Parts.push(`load:${ollamaLoaded}`);
|
|
262
|
-
if (footerNativeCtx) line2Parts.push(`M:${footerNativeCtx}`);
|
|
263
|
-
if (footerCtxPct) line2Parts.push(`S:${footerCtxPct}`);
|
|
264
|
-
if (isLocalProvider) {
|
|
265
|
-
line2Parts.push(`RAM ${fmtBytes(memUsed)}/${fmtBytes(memTotal)}`);
|
|
266
|
-
if (hasSwap && swapUsed > 0) {
|
|
267
|
-
line2Parts.push(`Swap ${fmtBytes(swapUsed)}/${fmtBytes(swapTotal)}`);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
if (lastUpstream > 0 || lastDownstream > 0) {
|
|
271
|
-
line2Parts.push(dim(`\u2191${fmtTk(lastUpstream)} \u2193${fmtTk(lastDownstream)}`));
|
|
272
|
-
}
|
|
273
|
-
if (lastResponseTime !== null) line2Parts.push(`Resp ${fmtDur(lastResponseTime)}`);
|
|
274
|
-
if (lastPayload) {
|
|
275
|
-
const params = extractParams(lastPayload);
|
|
276
|
-
if (params.length > 0) line2Parts.push(...params.map((p) => dim(p)));
|
|
277
|
-
}
|
|
278
|
-
const now = Date.now();
|
|
279
|
-
if (securityFlashTool && now < securityFlashUntil) {
|
|
280
|
-
line2Parts.push(red(`BLOCKED:${securityFlashTool}`));
|
|
281
|
-
}
|
|
282
|
-
if (blockedCount > 0) {
|
|
283
|
-
line2Parts.push(red(`SEC:${blockedCount}`));
|
|
284
|
-
}
|
|
285
|
-
let line2 = truncateLine(line2Parts.join(sep), width);
|
|
286
|
-
if (line2) lines.push(line2);
|
|
287
|
-
if (activeTool && activeToolStart > 0) {
|
|
288
|
-
const elapsed = performance.now() - activeToolStart;
|
|
289
|
-
lines.push(`${yellow("\u23F3")} ${activeTool}: ${fmtDur(elapsed)}`);
|
|
290
|
-
}
|
|
291
|
-
return lines;
|
|
292
|
-
},
|
|
293
|
-
invalidate() {
|
|
294
|
-
},
|
|
295
|
-
dispose() {
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
});
|
|
299
222
|
if (updateInterval) clearInterval(updateInterval);
|
|
300
|
-
updateInterval = setInterval(
|
|
301
|
-
updateMetrics();
|
|
302
|
-
if (tuiRef) tuiRef.requestRender();
|
|
303
|
-
}, 3e3);
|
|
223
|
+
updateInterval = setInterval(updateMetrics, STATUS_UPDATE_INTERVAL_MS);
|
|
304
224
|
});
|
|
305
|
-
pi.on("session_shutdown", async () => {
|
|
306
|
-
if (updateInterval)
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
if (ctxUi) {
|
|
310
|
-
ctxUi.setFooter(void 0);
|
|
311
|
-
ctxUi = null;
|
|
225
|
+
pi.on("session_shutdown", async (_event, ctx) => {
|
|
226
|
+
if (updateInterval) {
|
|
227
|
+
clearInterval(updateInterval);
|
|
228
|
+
updateInterval = null;
|
|
312
229
|
}
|
|
230
|
+
if (toolTimerInterval) {
|
|
231
|
+
clearInterval(toolTimerInterval);
|
|
232
|
+
toolTimerInterval = null;
|
|
233
|
+
}
|
|
234
|
+
ctxUi = null;
|
|
313
235
|
currentCtx = null;
|
|
236
|
+
const ui = ctx?.ui;
|
|
237
|
+
if (ui) {
|
|
238
|
+
ui.setStatus("status-cpu", void 0);
|
|
239
|
+
ui.setStatus("status-ram", void 0);
|
|
240
|
+
ui.setStatus("status-swap", void 0);
|
|
241
|
+
ui.setStatus("status-native-ctx", void 0);
|
|
242
|
+
ui.setStatus("status-resp", void 0);
|
|
243
|
+
ui.setStatus("status-resp-max", void 0);
|
|
244
|
+
ui.setStatus("status-params", void 0);
|
|
245
|
+
ui.setStatus("system-prompt", void 0);
|
|
246
|
+
ui.setStatus("status-sec", void 0);
|
|
247
|
+
ui.setStatus("status-tool", void 0);
|
|
248
|
+
ui.setStatus("status-versions", void 0);
|
|
249
|
+
}
|
|
314
250
|
securityFlashTool = "";
|
|
315
251
|
securityFlashUntil = 0;
|
|
316
252
|
activeTool = "";
|
|
317
253
|
activeToolStart = 0;
|
|
318
254
|
blockedCount = 0;
|
|
319
|
-
|
|
320
|
-
|
|
255
|
+
lastResponseTime = null;
|
|
256
|
+
lastPayload = null;
|
|
257
|
+
versionsText = "";
|
|
258
|
+
cachedPromptText = null;
|
|
321
259
|
});
|
|
322
260
|
pi.on("before_provider_request", (event) => {
|
|
323
261
|
lastPayload = event.payload;
|
|
324
262
|
});
|
|
325
|
-
|
|
326
|
-
if (event?.message?.role !== "assistant") return;
|
|
327
|
-
const usage = event?.message?.usage ?? // normalised Pi usage
|
|
328
|
-
event?.usage ?? // alternative path
|
|
329
|
-
null;
|
|
330
|
-
if (!usage) return;
|
|
331
|
-
const inp = usage.input ?? usage.promptTokens ?? usage.prompt_tokens;
|
|
332
|
-
const out = usage.output ?? usage.completionTokens ?? usage.completion_tokens;
|
|
333
|
-
if (inp != null) lastUpstream = inp;
|
|
334
|
-
if (out != null) lastDownstream = out;
|
|
335
|
-
if (tuiRef) tuiRef.requestRender();
|
|
336
|
-
}
|
|
337
|
-
pi.on("message_end", captureUsage);
|
|
338
|
-
pi.on("turn_end", captureUsage);
|
|
339
|
-
pi.on("agent_start", async () => {
|
|
263
|
+
pi.on("agent_start", async (_event, ctx) => {
|
|
340
264
|
agentStartTime = performance.now();
|
|
341
|
-
|
|
342
|
-
|
|
265
|
+
try {
|
|
266
|
+
const prompt = ctx.getSystemPrompt();
|
|
267
|
+
const chr = prompt.length;
|
|
268
|
+
const tok = prompt.split(/\s+/).filter(Boolean).length;
|
|
269
|
+
cachedPromptText = `${dim("Prompt:")} ${green(`${chr} chr ${tok} tok`)}`;
|
|
270
|
+
} catch {
|
|
271
|
+
}
|
|
272
|
+
flushStatus();
|
|
343
273
|
});
|
|
344
274
|
pi.on("agent_end", async () => {
|
|
345
275
|
if (agentStartTime !== null) {
|
|
@@ -348,29 +278,40 @@ function status_temp_default(pi) {
|
|
|
348
278
|
}
|
|
349
279
|
activeTool = "";
|
|
350
280
|
activeToolStart = 0;
|
|
281
|
+
stopToolTimer();
|
|
351
282
|
updateMetrics();
|
|
352
|
-
if (tuiRef) tuiRef.requestRender();
|
|
353
283
|
});
|
|
284
|
+
function startToolTimer() {
|
|
285
|
+
if (toolTimerInterval) return;
|
|
286
|
+
toolTimerInterval = setInterval(flushStatus, TOOL_TIMER_INTERVAL_MS);
|
|
287
|
+
}
|
|
288
|
+
function stopToolTimer() {
|
|
289
|
+
if (toolTimerInterval) {
|
|
290
|
+
clearInterval(toolTimerInterval);
|
|
291
|
+
toolTimerInterval = null;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
354
294
|
pi.on("tool_call", (event) => {
|
|
355
295
|
if (!event) return;
|
|
356
296
|
const isBlocked = event.blocked === true || event.blocked === "true" || event.result?.blocked === true || event.error?.includes("blocked");
|
|
357
297
|
if (isBlocked) {
|
|
358
298
|
securityFlashTool = event.tool ?? event.name ?? "unknown";
|
|
359
299
|
securityFlashUntil = Date.now() + 3e3;
|
|
360
|
-
|
|
361
|
-
|
|
300
|
+
blockedCount++;
|
|
301
|
+
flushStatus();
|
|
362
302
|
}
|
|
363
303
|
});
|
|
364
304
|
pi.on("tool_execution_start", (event) => {
|
|
365
305
|
if (!event) return;
|
|
366
306
|
activeTool = event.tool ?? event.name ?? "tool";
|
|
367
307
|
activeToolStart = performance.now();
|
|
368
|
-
|
|
308
|
+
startToolTimer();
|
|
369
309
|
});
|
|
370
310
|
pi.on("tool_execution_end", () => {
|
|
371
311
|
activeTool = "";
|
|
372
312
|
activeToolStart = 0;
|
|
373
|
-
|
|
313
|
+
stopToolTimer();
|
|
314
|
+
flushStatus();
|
|
374
315
|
});
|
|
375
316
|
}
|
|
376
317
|
export {
|