oc-metricboard 0.1.7 → 0.1.8
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 +11 -6
- package/src/turn-state.ts +15 -1
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,
|
|
3
|
+
import { getDisplayInputTokens, getDisplayOutputTokens, 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,15 @@ export function createCollector(
|
|
|
352
352
|
|
|
353
353
|
const cacheReadCompleteness: CacheReadCompleteness =
|
|
354
354
|
exactCacheCount === 0 ? "unknown" : exactCacheCount === metrics.length ? "exact" : "partial"
|
|
355
|
-
|
|
355
|
+
// Model rows use the same turn-level TTFT as the main aggregate: the
|
|
356
|
+
// earliest gated turn TTFT across the group's sessions, falling back to
|
|
357
|
+
// per-request TTFT when no turn timing exists (e.g. sub-agent sessions
|
|
358
|
+
// whose turn start coincides with their first request).
|
|
359
|
+
let ttft: number | null = null
|
|
360
|
+
for (const m of metrics) {
|
|
361
|
+
const candidate = getTurnTtft(state.turns.get(m.sessionID), getTtft(m))
|
|
362
|
+
if (candidate !== null && (ttft === null || candidate < ttft)) ttft = candidate
|
|
363
|
+
}
|
|
356
364
|
|
|
357
365
|
// Live TPS for this model group
|
|
358
366
|
let liveTps = 0
|
|
@@ -551,10 +559,7 @@ export function createCollector(
|
|
|
551
559
|
// collapse to ~0). Anchor TTFT to the turn's user message instead —
|
|
552
560
|
// stable across all steps within a turn, refreshed on each new turn.
|
|
553
561
|
// Falls back to the per-request measurement when no turn timing exists.
|
|
554
|
-
const
|
|
555
|
-
? gateTtft(foregroundTurn.firstTokenTime - foregroundTurn.turnStartTime)
|
|
556
|
-
: null
|
|
557
|
-
const ttft = turnTtft ?? (foregroundRequest ? getTtft(foregroundRequest) : null)
|
|
562
|
+
const ttft = getTurnTtft(foregroundTurn, foregroundRequest ? getTtft(foregroundRequest) : null)
|
|
558
563
|
|
|
559
564
|
const result: MetricsAggregate = {
|
|
560
565
|
sessionIDs: contributingSessionIDs.length > 0 ? contributingSessionIDs : [rootID],
|
package/src/turn-state.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getDisplayInputTokens, getDisplayOutputTokens } from "./metrics"
|
|
1
|
+
import { gateTtft, getDisplayInputTokens, getDisplayOutputTokens } from "./metrics"
|
|
2
2
|
import type { RequestMetrics, TurnMetrics } from "./types"
|
|
3
3
|
|
|
4
4
|
export function createTurnMetrics(sessionID: string, now: number): TurnMetrics {
|
|
@@ -94,3 +94,17 @@ export function completeTurn(turn: TurnMetrics, now: number): void {
|
|
|
94
94
|
export function recordTurnFirstToken(turn: TurnMetrics, now: number): void {
|
|
95
95
|
if (turn.firstTokenTime === null) turn.firstTokenTime = now
|
|
96
96
|
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Turn-level TTFT (user message → first token), gated. Falls back to the
|
|
100
|
+
* supplied per-request TTFT when the turn has no first-token timing. This is
|
|
101
|
+
* the ONLY meaningful TTFT observable from opencode's event stream for
|
|
102
|
+
* intra-turn steps, so every TTFT display path should prefer it.
|
|
103
|
+
*/
|
|
104
|
+
export function getTurnTtft(turn: TurnMetrics | undefined, fallback: number | null = null): number | null {
|
|
105
|
+
if (turn?.firstTokenTime != null) {
|
|
106
|
+
const gated = gateTtft(turn.firstTokenTime - turn.turnStartTime)
|
|
107
|
+
if (gated !== null) return gated
|
|
108
|
+
}
|
|
109
|
+
return fallback
|
|
110
|
+
}
|