minecodex 2.0.26 → 2.0.27
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.
|
@@ -10,26 +10,16 @@ function usageRecord(row) {
|
|
|
10
10
|
|| !Number.isFinite(row.timestamp) || !Number.isFinite(row.durationMs) || row.durationMs < 0) return null;
|
|
11
11
|
return { id:row.requestId, conversationId:row.conversationId, start:row.timestamp,
|
|
12
12
|
end:row.timestamp+row.durationMs, duration:row.durationMs,
|
|
13
|
-
first:row.firstOutputMs, generationStart:row.genStartMs, generationEnd:row.lastOutputMs,
|
|
14
13
|
usageStatus:row.usageStatus, input:row.usage?.inputTokens, cached:row.usage?.cachedInputTokens ?? 0,
|
|
15
14
|
output:row.usage?.outputTokens };
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
function
|
|
17
|
+
function requestMeasurement(record) {
|
|
19
18
|
const unavailable = reason => ({source:"ocx",output:record.output,elapsed:null,reason});
|
|
20
19
|
if (record.usageStatus === "unsupported") return unavailable("usage_unsupported");
|
|
21
20
|
if (!Number.isFinite(record.output) || record.output <= 0) return unavailable("output_missing");
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
elapsed=record.generationEnd-record.generationStart;
|
|
25
|
-
} else {
|
|
26
|
-
if (record.first === undefined) return unavailable("ttft_missing");
|
|
27
|
-
if (!Number.isFinite(record.first) || record.first < 0) return unavailable("invalid_duration");
|
|
28
|
-
elapsed=record.duration-record.first;
|
|
29
|
-
}
|
|
30
|
-
if (!Number.isFinite(elapsed) || elapsed <= 0) return unavailable("invalid_duration");
|
|
31
|
-
if (elapsed < 1000) return unavailable("decode_window_too_short");
|
|
32
|
-
return {source:"ocx",output:record.output,elapsed,reason:null};
|
|
21
|
+
if (!Number.isFinite(record.duration) || record.duration <= 0) return unavailable("invalid_duration");
|
|
22
|
+
return {source:"ocx",output:record.output,elapsed:record.duration,reason:null};
|
|
33
23
|
}
|
|
34
24
|
|
|
35
25
|
export class OpenCodexUsageReader {
|
|
@@ -85,6 +75,6 @@ export class OpenCodexUsageReader {
|
|
|
85
75
|
owners.set(record.id,(owners.get(record.id) ?? 0)+1);
|
|
86
76
|
}
|
|
87
77
|
return new Map([...candidates].filter(([,record])=>owners.get(record.id) === 1)
|
|
88
|
-
.map(([id,record])=>[id,
|
|
78
|
+
.map(([id,record])=>[id,requestMeasurement(record)]));
|
|
89
79
|
}
|
|
90
80
|
}
|
|
@@ -104,38 +104,16 @@ export function applySessionStatusEvent(state, event) {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
export function sessionStatusSnapshot(state, threadId, measurements = new Map()) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (!sample.turnId) continue;
|
|
118
|
-
unavailableSource=source;
|
|
119
|
-
unavailableReason=measurement?.reason ?? (Number.isFinite(elapsed) && elapsed > 0 && elapsed < 1000
|
|
120
|
-
? "decode_window_too_short" : "timing_missing");
|
|
121
|
-
if (!Number.isFinite(elapsed) || elapsed < 1000) continue;
|
|
122
|
-
const turn = turnSpeeds.get(sample.turnId) ?? { tokens:0, ms:0, samples:0, sources:new Set() };
|
|
123
|
-
turn.tokens += measurement?.output ?? sample.output;
|
|
124
|
-
turn.ms += elapsed;
|
|
125
|
-
turn.samples += 1;
|
|
126
|
-
turn.sources.add(source);
|
|
127
|
-
turnSpeeds.set(sample.turnId, turn);
|
|
128
|
-
}
|
|
129
|
-
// 按回合顺序取最近五个有效回合;同轮多步合并,无数据的回合不占名额。
|
|
130
|
-
const recentTurns = [...state.turns].filter(id => turnSpeeds.has(id)).slice(-5);
|
|
131
|
-
const speedSources = new Set();
|
|
132
|
-
for (const id of recentTurns) {
|
|
133
|
-
const turn = turnSpeeds.get(id);
|
|
134
|
-
decodeTokens += turn.tokens;
|
|
135
|
-
decodeMs += turn.ms;
|
|
136
|
-
speedSamples += turn.samples;
|
|
137
|
-
for (const source of turn.sources) speedSources.add(source);
|
|
138
|
-
}
|
|
107
|
+
const sample = state.speedMeasurements.at(-1);
|
|
108
|
+
const measurement = measurements.get(sample?.id);
|
|
109
|
+
const source = measurement?.source ?? "codex";
|
|
110
|
+
const elapsed = measurement ? measurement.elapsed : sample?.start == null ? null
|
|
111
|
+
: sample.end - sample.start - boundedToolWaitMs(sample.tools, sample.start, sample.end, sample.outputs);
|
|
112
|
+
const valid = Boolean(sample?.turnId) && Number.isFinite(elapsed) && elapsed > 0
|
|
113
|
+
&& (source === "ocx" || elapsed >= 1000);
|
|
114
|
+
const output = measurement?.output ?? sample?.output;
|
|
115
|
+
const unavailableReason = measurement?.reason ?? (Number.isFinite(elapsed) && elapsed > 0 && elapsed < 1000
|
|
116
|
+
? "decode_window_too_short" : "timing_missing");
|
|
139
117
|
const total = state.total;
|
|
140
118
|
const input = total?.input ?? 0;
|
|
141
119
|
const cached = total?.cached ?? 0;
|
|
@@ -154,11 +132,11 @@ export function sessionStatusSnapshot(state, threadId, measurements = new Map())
|
|
|
154
132
|
uncachedInputTokens: total ? Math.max(0, input - cached - cacheWrite) : null,
|
|
155
133
|
outputTokens: total?.output ?? null,
|
|
156
134
|
cacheHitPercent: input > 0 ? Math.round(cached / input * 100) : null,
|
|
157
|
-
observedTps:
|
|
158
|
-
speedSamples,
|
|
159
|
-
speedSource:
|
|
160
|
-
speedUnavailableReason:
|
|
161
|
-
observedModelMs:
|
|
135
|
+
observedTps: valid ? Math.round(output / (elapsed / 1000)) : null,
|
|
136
|
+
speedSamples: valid ? 1 : 0,
|
|
137
|
+
speedSource: source,
|
|
138
|
+
speedUnavailableReason: valid ? null : unavailableReason,
|
|
139
|
+
observedModelMs: valid ? elapsed : 0,
|
|
162
140
|
toolMs: state.toolMs,
|
|
163
141
|
averageFirstTokenMs: state.ttftSamples > 0 ? Math.round(state.ttftTotalMs / state.ttftSamples) : null,
|
|
164
142
|
contextUsedTokens: contextUsed,
|
|
@@ -8,9 +8,9 @@ const copyByLocale = { "zh-CN": {
|
|
|
8
8
|
sum: "合计", capacity: "窗口容量", contextShare: "上下文占用", compactions: "压缩次数",
|
|
9
9
|
instructions: "指令", messages: "消息", toolHistory: "工具交互", other: "未分类",
|
|
10
10
|
speedHelp: "关于 TPS", speedInfo: "根据会话日志估算生成速度,包含推理输出。",
|
|
11
|
-
speedInfoOcx: "根据 OCX
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
speedInfoOcx: "根据 OCX 记录计算响应速度,包含推理输出和请求等待时间。",
|
|
12
|
+
speedWindow: "取最近一次已完成响应的数据,仅供参考。",
|
|
13
|
+
speedWindowOcx: "取最近一次请求的记录,与 OCX 的 TPS 一致。",
|
|
14
14
|
speedUnavailable: "有效计时不足,暂无法估算。",
|
|
15
15
|
}, en: {
|
|
16
16
|
turns: "turns", steps: "steps", speed: "TPS", cache: "Cache", cacheDetail: "Cache hit",
|
|
@@ -19,9 +19,9 @@ const copyByLocale = { "zh-CN": {
|
|
|
19
19
|
sum: "Sum", capacity: "Window size", contextShare: "Context used", compactions: "Compactions",
|
|
20
20
|
instructions: "Instructions", messages: "Messages", toolHistory: "Tool activity", other: "Unclassified",
|
|
21
21
|
speedHelp: "About TPS", speedInfo: "Generation speed estimated from session logs, including reasoning output.",
|
|
22
|
-
speedInfoOcx: "
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
speedInfoOcx: "Response speed calculated from OCX records, including reasoning output and request waiting time.",
|
|
23
|
+
speedWindow: "Uses the latest completed response. For reference only.",
|
|
24
|
+
speedWindowOcx: "Uses the latest request record, matching OCX TPS.",
|
|
25
25
|
speedUnavailable: "Not enough valid timing data to estimate speed.",
|
|
26
26
|
} };
|
|
27
27
|
function selectedCopy() {
|
|
@@ -31,8 +31,9 @@ function selectedCopy() {
|
|
|
31
31
|
|
|
32
32
|
function speedTooltip(value, copy) {
|
|
33
33
|
const source = value.speedSource === "ocx" ? copy.speedInfoOcx
|
|
34
|
-
:
|
|
35
|
-
|
|
34
|
+
: copy.speedInfo;
|
|
35
|
+
const window = value.speedSource === "ocx" ? copy.speedWindowOcx : copy.speedWindow;
|
|
36
|
+
return `${source} ${value.observedTps == null ? copy.speedUnavailable : window}`;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
// 图标来自 Lucide Static 与 Phosphor Icons;许可见 vendor/。
|