oc-metricboard 0.1.5 → 0.1.6
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 +1 -1
- package/src/collector.ts +2 -2
- package/src/metrics.ts +12 -4
- package/src/request-state.ts +12 -7
package/package.json
CHANGED
package/src/collector.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { TuiPluginApi } from "@opencode-ai/plugin/tui"
|
|
2
2
|
import type { BarConfig, CacheReadCompleteness, MetricsAggregate, MetricsScope, ModelMetrics, RequestMetrics } from "./types"
|
|
3
|
-
import { getDisplayInputTokens, getDisplayOutputTokens, getTtft } from "./metrics"
|
|
3
|
+
import { getDisplayInputTokens, getDisplayOutputTokens, gateTtft, getTtft } from "./metrics"
|
|
4
4
|
import { registerEventHandlers } from "./event-handlers"
|
|
5
5
|
import type { CollectorState } from "./collector-state"
|
|
6
6
|
import type { MetricsEventApi } from "./event-bus"
|
|
@@ -352,7 +352,7 @@ export function createCollector(
|
|
|
352
352
|
|
|
353
353
|
const cacheReadCompleteness: CacheReadCompleteness =
|
|
354
354
|
exactCacheCount === 0 ? "unknown" : exactCacheCount === metrics.length ? "exact" : "partial"
|
|
355
|
-
const ttft = firstTokenTime === null ? null :
|
|
355
|
+
const ttft = firstTokenTime === null ? null : gateTtft(firstTokenTime - requestStartTime)
|
|
356
356
|
|
|
357
357
|
// Live TPS for this model group
|
|
358
358
|
let liveTps = 0
|
package/src/metrics.ts
CHANGED
|
@@ -81,7 +81,7 @@ export function aggregateRequestMetrics(
|
|
|
81
81
|
|
|
82
82
|
const cacheReadCompleteness: CacheReadCompleteness =
|
|
83
83
|
exactCacheCount === 0 ? "unknown" : exactCacheCount === metrics.length ? "exact" : "partial"
|
|
84
|
-
const ttft = firstTokenTime === null ? null :
|
|
84
|
+
const ttft = firstTokenTime === null ? null : gateTtft(firstTokenTime - requestStartTime)
|
|
85
85
|
const sessionIDs = [...new Set(metrics.map((m) => m.sessionID))]
|
|
86
86
|
|
|
87
87
|
return {
|
|
@@ -98,6 +98,7 @@ export function aggregateRequestMetrics(
|
|
|
98
98
|
liveTps: null,
|
|
99
99
|
isStreaming,
|
|
100
100
|
isComplete,
|
|
101
|
+
modelBreakdown: [],
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
104
|
|
|
@@ -112,11 +113,18 @@ export function aggregateRequestMetrics(
|
|
|
112
113
|
*/
|
|
113
114
|
export const MAX_TTFT_MS = 10 * 60 * 1000
|
|
114
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Gate a raw TTFT value: non-finite, negative, or beyond MAX_TTFT_MS is not a
|
|
118
|
+
* meaningful TTFT and is reported as null (rendered "--").
|
|
119
|
+
*/
|
|
120
|
+
export function gateTtft(rawMs: number): number | null {
|
|
121
|
+
if (!Number.isFinite(rawMs) || rawMs < 0 || rawMs > MAX_TTFT_MS) return null
|
|
122
|
+
return Math.round(rawMs)
|
|
123
|
+
}
|
|
124
|
+
|
|
115
125
|
export function getTtft(m: RequestMetrics): number | null {
|
|
116
126
|
if (m.firstTokenTime === null) return null
|
|
117
|
-
|
|
118
|
-
if (!Number.isFinite(ttft) || ttft < 0 || ttft > MAX_TTFT_MS) return null
|
|
119
|
-
return Math.round(ttft)
|
|
127
|
+
return gateTtft(m.firstTokenTime - m.requestStartTime)
|
|
120
128
|
}
|
|
121
129
|
|
|
122
130
|
/**
|
package/src/request-state.ts
CHANGED
|
@@ -38,13 +38,18 @@ export function currentRequest(input: CurrentRequestInput): RequestMetrics {
|
|
|
38
38
|
? startTurn(input.state.turns, input.sessionID, input.now)
|
|
39
39
|
: ensureTurn(input.state.turns, input.sessionID, existing?.requestStartTime ?? input.now)
|
|
40
40
|
if (existing && isDifferentMessage && !startsAfterCompletedTurn) retireRequestIntoTurn(turn, existing)
|
|
41
|
-
// Keep the existing request's start time
|
|
42
|
-
// opencode 1.18.x stamps
|
|
43
|
-
//
|
|
44
|
-
// the correct "request submitted" anchor.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
// Keep the existing request's start time ONLY while the existing request
|
|
42
|
+
// is still an un-streamed placeholder (opencode 1.18.x stamps
|
|
43
|
+
// step.started lazily at the first token, so the user message's created
|
|
44
|
+
// time is the correct "request submitted" anchor). Once the previous
|
|
45
|
+
// request has produced a first token it was a real generation, and a new
|
|
46
|
+
// messageID is a NEW step: it must NOT inherit the turn's original start
|
|
47
|
+
// time, otherwise TTFT absorbs every tool execution since the turn began
|
|
48
|
+
// (huge TTFT in long agentic sessions).
|
|
49
|
+
const inheritAnchor = !startsAfterCompletedTurn && (existing?.firstTokenTime ?? null) === null
|
|
50
|
+
const requestStartTime = inheritAnchor
|
|
51
|
+
? (existing?.requestStartTime ?? input.now)
|
|
52
|
+
: input.now
|
|
48
53
|
const current = createFreshMetrics(
|
|
49
54
|
input.sessionID,
|
|
50
55
|
input.messageID,
|