pi-metrics 0.4.2 → 0.5.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/package.json +2 -2
- package/src/index.ts +39 -18
- package/src/notice.ts +13 -0
- package/src/tps.ts +6 -4
- package/src/turn-elapsed.ts +4 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-metrics",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Pi metrics extension: elapsed-time HUD and resilient TPS telemetry",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.ts",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"@earendil-works/pi-tui": ">=0.80.0"
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"pi-extensions-i18n": "^0.
|
|
65
|
+
"pi-extensions-i18n": "^0.5.0"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
68
|
"@earendil-works/pi-ai": "0.85.1",
|
package/src/index.ts
CHANGED
|
@@ -3,7 +3,8 @@ import type {
|
|
|
3
3
|
ExtensionCommandContext,
|
|
4
4
|
ExtensionContext,
|
|
5
5
|
} from "@earendil-works/pi-coding-agent";
|
|
6
|
-
import { createTranslator, loadCatalog } from "pi-extensions-i18n";
|
|
6
|
+
import { createTranslator, loadCatalog, notifyWithSource } from "pi-extensions-i18n";
|
|
7
|
+
import { NOTICE_SOURCE } from "./notice.ts";
|
|
7
8
|
import turnElapsed from "./turn-elapsed.ts";
|
|
8
9
|
import tps from "./tps.ts";
|
|
9
10
|
import { configPath, loadConfig, parseConfig, saveConfig, type MetricsConfig } from "./config.ts";
|
|
@@ -29,32 +30,42 @@ function registerConfigCommand(pi: ExtensionAPI): void {
|
|
|
29
30
|
handler: async (args: string, ctx: ExtensionCommandContext): Promise<void> => {
|
|
30
31
|
const value = args.trim();
|
|
31
32
|
if (value && value !== CONFIG_RESET_COMMAND && value !== ENABLE_COMMAND && value !== DISABLE_COMMAND) {
|
|
32
|
-
ctx
|
|
33
|
+
notifyWithSource({ ctx, source: NOTICE_SOURCE, level: NOTICE_WARNING, message: i18n.t("configCommandUsage") });
|
|
33
34
|
return;
|
|
34
35
|
}
|
|
35
36
|
if (value === CONFIG_RESET_COMMAND || value === ENABLE_COMMAND || value === DISABLE_COMMAND) {
|
|
36
37
|
try {
|
|
37
38
|
const config = parseConfig(value === CONFIG_RESET_COMMAND ? {} : { enabled: value === ENABLE_COMMAND });
|
|
38
39
|
const path = saveConfig(config);
|
|
39
|
-
ctx
|
|
40
|
+
notifyWithSource({ ctx, source: NOTICE_SOURCE, level: NOTICE_INFO, message: i18n.t("configCommandSaved", { path }) });
|
|
40
41
|
} catch (error) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
notifyWithSource({
|
|
43
|
+
ctx,
|
|
44
|
+
source: NOTICE_SOURCE,
|
|
45
|
+
level: NOTICE_ERROR,
|
|
46
|
+
message: i18n.t("configCommandInvalid", {
|
|
47
|
+
error: error instanceof Error ? error.message : String(error),
|
|
48
|
+
}),
|
|
49
|
+
});
|
|
44
50
|
}
|
|
45
51
|
return;
|
|
46
52
|
}
|
|
47
53
|
if (!ctx.hasUI) {
|
|
48
|
-
ctx
|
|
54
|
+
notifyWithSource({ ctx, source: NOTICE_SOURCE, level: NOTICE_WARNING, message: i18n.t("configCommandInteractiveOnly") });
|
|
49
55
|
return;
|
|
50
56
|
}
|
|
51
57
|
let current: MetricsConfig;
|
|
52
58
|
try {
|
|
53
59
|
current = loadConfig();
|
|
54
60
|
} catch (error) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
notifyWithSource({
|
|
62
|
+
ctx,
|
|
63
|
+
source: NOTICE_SOURCE,
|
|
64
|
+
level: NOTICE_ERROR,
|
|
65
|
+
message: i18n.t("configCommandInvalid", {
|
|
66
|
+
error: error instanceof Error ? error.message : String(error),
|
|
67
|
+
}),
|
|
68
|
+
});
|
|
58
69
|
return;
|
|
59
70
|
}
|
|
60
71
|
const enabledChoice = i18n.t("configEnabled", { value: i18n.t(current.enabled ? "configOn" : "configOff") });
|
|
@@ -69,11 +80,16 @@ function registerConfigCommand(pi: ExtensionAPI): void {
|
|
|
69
80
|
const choice = selected === enabledChoice ? CONFIG_CHOICE.enabled : CONFIG_CHOICE.disabled;
|
|
70
81
|
try {
|
|
71
82
|
const path = saveConfig({ enabled: choice === CONFIG_CHOICE.enabled });
|
|
72
|
-
ctx
|
|
83
|
+
notifyWithSource({ ctx, source: NOTICE_SOURCE, level: NOTICE_INFO, message: i18n.t("configCommandSaved", { path }) });
|
|
73
84
|
} catch (error) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
85
|
+
notifyWithSource({
|
|
86
|
+
ctx,
|
|
87
|
+
source: NOTICE_SOURCE,
|
|
88
|
+
level: NOTICE_ERROR,
|
|
89
|
+
message: i18n.t("configCommandInvalid", {
|
|
90
|
+
error: error instanceof Error ? error.message : String(error),
|
|
91
|
+
}),
|
|
92
|
+
});
|
|
77
93
|
}
|
|
78
94
|
},
|
|
79
95
|
};
|
|
@@ -93,10 +109,15 @@ export default function piHud(pi: ExtensionAPI): void {
|
|
|
93
109
|
}
|
|
94
110
|
if (configError !== undefined) {
|
|
95
111
|
pi.on("session_start", (_event, ctx: ExtensionContext) => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
112
|
+
notifyWithSource({
|
|
113
|
+
ctx,
|
|
114
|
+
source: NOTICE_SOURCE,
|
|
115
|
+
level: NOTICE_WARNING,
|
|
116
|
+
message: i18n.t("configLoadFailed", {
|
|
117
|
+
path: configPath(),
|
|
118
|
+
error: configError instanceof Error ? configError.message : String(configError),
|
|
119
|
+
}),
|
|
120
|
+
});
|
|
100
121
|
});
|
|
101
122
|
}
|
|
102
123
|
if (!config.enabled) return;
|
package/src/notice.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 本扩展统一的提示来源定义。
|
|
3
|
+
* 所有 notifyWithSource 调用共用同一份标签与颜色,避免两个入口不一致。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { NoticeColor, NoticeSource } from "pi-extensions-i18n";
|
|
7
|
+
|
|
8
|
+
/** 本扩展的提示标签;短且唯一,便于在会话里定位来源。 */
|
|
9
|
+
export const NOTICE_TAG = "metrics";
|
|
10
|
+
/** 提示标签颜色;与其它扩展错开,避免看起来像同一条消息。 */
|
|
11
|
+
export const NOTICE_COLOR: NoticeColor = "dim";
|
|
12
|
+
/** 本扩展的提示来源。 */
|
|
13
|
+
export const NOTICE_SOURCE: NoticeSource = { tag: NOTICE_TAG, color: NOTICE_COLOR };
|
package/src/tps.ts
CHANGED
|
@@ -11,7 +11,9 @@ import type {
|
|
|
11
11
|
ExtensionAPI,
|
|
12
12
|
ExtensionContext,
|
|
13
13
|
} from "@earendil-works/pi-coding-agent";
|
|
14
|
+
import { notifyWithSource } from "pi-extensions-i18n";
|
|
14
15
|
import { i18n } from "./i18n.ts";
|
|
16
|
+
import { NOTICE_SOURCE } from "./notice.ts";
|
|
15
17
|
|
|
16
18
|
interface TurnStartEvent {
|
|
17
19
|
type: "turn_start";
|
|
@@ -330,11 +332,11 @@ function restoreTPSNotification(
|
|
|
330
332
|
const data = entry.data as Record<string, unknown> | null | undefined;
|
|
331
333
|
if (!data) continue;
|
|
332
334
|
if (typeof data.model === "object" && data.model !== null) {
|
|
333
|
-
schedule(() => ctx
|
|
335
|
+
schedule(() => notifyWithSource({ ctx, source: NOTICE_SOURCE, level: "info", message: composeDisplayString(data as unknown as TurnTelemetry) }));
|
|
334
336
|
return;
|
|
335
337
|
}
|
|
336
338
|
if (typeof data.message === "string") {
|
|
337
|
-
schedule(() => ctx
|
|
339
|
+
schedule(() => notifyWithSource({ ctx, source: NOTICE_SOURCE, level: "info", message: data.message as string }));
|
|
338
340
|
return;
|
|
339
341
|
}
|
|
340
342
|
}
|
|
@@ -392,7 +394,7 @@ export default function tpsExtension(pi: ExtensionAPI): void {
|
|
|
392
394
|
committed.telemetry = corrected;
|
|
393
395
|
pi.appendEntry("tps", corrected);
|
|
394
396
|
pi.events?.emit("tps:telemetry", corrected);
|
|
395
|
-
if (committed.ctx.hasUI) committed.ctx
|
|
397
|
+
if (committed.ctx.hasUI) notifyWithSource({ ctx: committed.ctx, source: NOTICE_SOURCE, level: "info", message: composeDisplayString(corrected) });
|
|
396
398
|
});
|
|
397
399
|
|
|
398
400
|
pi.on("session_shutdown", () => {
|
|
@@ -513,7 +515,7 @@ export default function tpsExtension(pi: ExtensionAPI): void {
|
|
|
513
515
|
};
|
|
514
516
|
pi.appendEntry("tps", telemetry);
|
|
515
517
|
pi.events?.emit("tps:telemetry", telemetry);
|
|
516
|
-
if (ctx.hasUI) ctx
|
|
518
|
+
if (ctx.hasUI) notifyWithSource({ ctx, source: NOTICE_SOURCE, level: "info", message: composeDisplayString(telemetry) });
|
|
517
519
|
});
|
|
518
520
|
|
|
519
521
|
}
|
package/src/turn-elapsed.ts
CHANGED
|
@@ -18,8 +18,10 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
21
|
+
import { notifyWithSource } from "pi-extensions-i18n";
|
|
21
22
|
import { formatDone, formatTick } from "./format-utils.ts";
|
|
22
23
|
import { i18n } from "./i18n.ts";
|
|
24
|
+
import { NOTICE_SOURCE } from "./notice.ts";
|
|
23
25
|
|
|
24
26
|
const TICK_MS = 1000;
|
|
25
27
|
|
|
@@ -74,7 +76,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
74
76
|
// 恢复 pi 默认 working 文字(下次 streaming 由 pi 内部重置)
|
|
75
77
|
ctx.ui.setWorkingMessage(undefined);
|
|
76
78
|
// 在 chat 流末尾插入一条 dim 灰文本
|
|
77
|
-
ctx
|
|
79
|
+
notifyWithSource({ ctx, source: NOTICE_SOURCE, level: "info", message: i18n.t("elapsedDone", { value: formatDone(elapsed) }) });
|
|
78
80
|
});
|
|
79
81
|
|
|
80
82
|
pi.on("agent_end", async (_event, ctx) => {
|
|
@@ -93,7 +95,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
93
95
|
|
|
94
96
|
ctx.ui.setWorkingMessage(undefined);
|
|
95
97
|
if (runElapsed > 0) {
|
|
96
|
-
ctx
|
|
98
|
+
notifyWithSource({ ctx, source: NOTICE_SOURCE, level: "info", message: i18n.t("elapsedTotal", { value: formatDone(runElapsed) }) });
|
|
97
99
|
}
|
|
98
100
|
});
|
|
99
101
|
}
|