@oh-my-pi/omp-stats 17.0.5 → 17.0.7
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/CHANGELOG.md +6 -0
- package/dist/client/index.css +1 -1
- package/dist/client/index.js +63 -63
- package/dist/client/styles.css +40 -55
- package/dist/types/client/data/view-models.d.ts +10 -3
- package/package.json +4 -4
- package/src/client/data/view-models.ts +16 -8
- package/src/client/routes/OverviewRoute.tsx +2 -2
- package/src/client/styles.css +4 -4
- package/src/client/ui/MetricCluster.tsx +13 -2
package/dist/client/styles.css
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
/*! tailwindcss v4.3.
|
|
1
|
+
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
2
2
|
@layer properties;
|
|
3
3
|
@layer theme, base, components, utilities;
|
|
4
4
|
@layer theme {
|
|
5
5
|
:root, :host {
|
|
6
|
-
--font-sans:
|
|
7
|
-
"
|
|
6
|
+
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
|
|
7
|
+
"Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
|
|
8
|
+
"Segoe UI Symbol", "Noto Color Emoji";
|
|
8
9
|
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
|
|
9
10
|
"Courier New", monospace;
|
|
10
11
|
--spacing: 0.25rem;
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
line-height: 1.5;
|
|
41
42
|
-webkit-text-size-adjust: 100%;
|
|
42
43
|
tab-size: 4;
|
|
43
|
-
font-family: var(--default-font-family,
|
|
44
|
+
font-family: var(--default-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
|
|
44
45
|
font-feature-settings: var(--default-font-feature-settings, normal);
|
|
45
46
|
font-variation-settings: var(--default-font-variation-settings, normal);
|
|
46
47
|
-webkit-tap-highlight-color: transparent;
|
|
@@ -92,7 +93,7 @@
|
|
|
92
93
|
border-color: inherit;
|
|
93
94
|
border-collapse: collapse;
|
|
94
95
|
}
|
|
95
|
-
:-moz-focusring {
|
|
96
|
+
:-moz-focusring:where(:not(iframe)) {
|
|
96
97
|
outline: auto;
|
|
97
98
|
}
|
|
98
99
|
progress {
|
|
@@ -251,7 +252,7 @@
|
|
|
251
252
|
max-width: 440px;
|
|
252
253
|
}
|
|
253
254
|
.min-w-0 {
|
|
254
|
-
min-width:
|
|
255
|
+
min-width: 0px;
|
|
255
256
|
}
|
|
256
257
|
.flex-1 {
|
|
257
258
|
flex: 1;
|
|
@@ -298,40 +299,30 @@
|
|
|
298
299
|
.gap-6 {
|
|
299
300
|
gap: calc(var(--spacing) * 6);
|
|
300
301
|
}
|
|
301
|
-
.space-y-0\.5 {
|
|
302
|
-
:
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
margin-block-end: calc(calc(var(--spacing) * 0.5) * calc(1 - var(--tw-space-y-reverse)));
|
|
306
|
-
}
|
|
302
|
+
:where(.space-y-0\.5 > :not(:last-child)) {
|
|
303
|
+
--tw-space-y-reverse: 0;
|
|
304
|
+
margin-block-start: calc(calc(var(--spacing) * 0.5) * var(--tw-space-y-reverse));
|
|
305
|
+
margin-block-end: calc(calc(var(--spacing) * 0.5) * calc(1 - var(--tw-space-y-reverse)));
|
|
307
306
|
}
|
|
308
|
-
.space-y-1 {
|
|
309
|
-
:
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
margin-block-end: calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)));
|
|
313
|
-
}
|
|
307
|
+
:where(.space-y-1 > :not(:last-child)) {
|
|
308
|
+
--tw-space-y-reverse: 0;
|
|
309
|
+
margin-block-start: calc(var(--spacing) * var(--tw-space-y-reverse));
|
|
310
|
+
margin-block-end: calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)));
|
|
314
311
|
}
|
|
315
|
-
.space-y-2 {
|
|
316
|
-
:
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
margin-block-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)));
|
|
320
|
-
}
|
|
312
|
+
:where(.space-y-2 > :not(:last-child)) {
|
|
313
|
+
--tw-space-y-reverse: 0;
|
|
314
|
+
margin-block-start: calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));
|
|
315
|
+
margin-block-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)));
|
|
321
316
|
}
|
|
322
|
-
.space-y-4 {
|
|
323
|
-
:
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)));
|
|
327
|
-
}
|
|
317
|
+
:where(.space-y-4 > :not(:last-child)) {
|
|
318
|
+
--tw-space-y-reverse: 0;
|
|
319
|
+
margin-block-start: calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));
|
|
320
|
+
margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)));
|
|
328
321
|
}
|
|
329
|
-
.space-y-6 {
|
|
330
|
-
:
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
margin-block-end: calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)));
|
|
334
|
-
}
|
|
322
|
+
:where(.space-y-6 > :not(:last-child)) {
|
|
323
|
+
--tw-space-y-reverse: 0;
|
|
324
|
+
margin-block-start: calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));
|
|
325
|
+
margin-block-end: calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)));
|
|
335
326
|
}
|
|
336
327
|
.truncate {
|
|
337
328
|
overflow: hidden;
|
|
@@ -466,30 +457,24 @@
|
|
|
466
457
|
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
|
467
458
|
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
|
468
459
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
background-color: var(--bg-hover);
|
|
473
|
-
}
|
|
460
|
+
@media (hover: hover) {
|
|
461
|
+
.hover\:bg-\[var\(--bg-hover\)\]:hover {
|
|
462
|
+
background-color: var(--bg-hover);
|
|
474
463
|
}
|
|
475
464
|
}
|
|
476
|
-
|
|
477
|
-
|
|
465
|
+
@media (width >= 48rem) {
|
|
466
|
+
.md\:grid-cols-3 {
|
|
478
467
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
479
468
|
}
|
|
480
|
-
|
|
481
|
-
.md\:grid-cols-6 {
|
|
482
|
-
@media (width >= 48rem) {
|
|
469
|
+
.md\:grid-cols-6 {
|
|
483
470
|
grid-template-columns: repeat(6, minmax(0, 1fr));
|
|
484
471
|
}
|
|
485
472
|
}
|
|
486
|
-
|
|
487
|
-
|
|
473
|
+
@media (width >= 64rem) {
|
|
474
|
+
.lg\:col-span-2 {
|
|
488
475
|
grid-column: span 2 / span 2;
|
|
489
476
|
}
|
|
490
|
-
|
|
491
|
-
.lg\:grid-cols-3 {
|
|
492
|
-
@media (width >= 64rem) {
|
|
477
|
+
.lg\:grid-cols-3 {
|
|
493
478
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
494
479
|
}
|
|
495
480
|
}
|
|
@@ -974,15 +959,15 @@
|
|
|
974
959
|
}
|
|
975
960
|
.stats-metric-secondary-grid {
|
|
976
961
|
display: grid;
|
|
977
|
-
grid-template-columns: repeat(
|
|
962
|
+
grid-template-columns: repeat(8, 1fr);
|
|
978
963
|
gap: 12px;
|
|
979
964
|
}
|
|
980
|
-
@media (max-width:
|
|
965
|
+
@media (max-width: 1279px) {
|
|
981
966
|
.stats-metric-secondary-grid {
|
|
982
|
-
grid-template-columns: repeat(
|
|
967
|
+
grid-template-columns: repeat(4, 1fr);
|
|
983
968
|
}
|
|
984
969
|
}
|
|
985
|
-
@media (max-width:
|
|
970
|
+
@media (max-width: 767px) {
|
|
986
971
|
.stats-metric-secondary-grid {
|
|
987
972
|
grid-template-columns: repeat(2, 1fr);
|
|
988
973
|
}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { AgentType, AgentTypeStats, BehaviorOverallStats, BehaviorTimeSeriesPoint, CostTimeSeriesPoint, FolderStats, ModelPerformancePoint, TimeRange, ToolUsageStats } from "../types.js";
|
|
2
|
+
export interface ConversationTokenStats {
|
|
3
|
+
totalInputTokens: number;
|
|
4
|
+
totalOutputTokens: number;
|
|
5
|
+
totalCacheReadTokens: number;
|
|
6
|
+
totalCacheWriteTokens: number;
|
|
7
|
+
}
|
|
8
|
+
/** Sum every conversation-token bucket shown by the overview. */
|
|
9
|
+
export declare function sumConversationTokens(stats: ConversationTokenStats): number;
|
|
2
10
|
export interface AgentTokenSegment {
|
|
3
11
|
agentType: AgentType;
|
|
4
12
|
/** input + output + cache read + cache write — the displayed denominator. */
|
|
@@ -16,9 +24,8 @@ export interface AgentTokenShareView {
|
|
|
16
24
|
/**
|
|
17
25
|
* Build the "token usage by agent" breakdown: one segment per agent type that
|
|
18
26
|
* appears in the data, ordered main -> subagents -> advisor, each carrying its
|
|
19
|
-
* token total and share of the grand total. Token counts
|
|
20
|
-
*
|
|
21
|
-
* segment's share never disagrees with the count beside it.
|
|
27
|
+
* token total and share of the grand total. Token counts use the same four
|
|
28
|
+
* conversation-token buckets as the overview total so the two views reconcile.
|
|
22
29
|
*/
|
|
23
30
|
export declare function buildAgentTokenShare(stats: AgentTypeStats[]): AgentTokenShareView;
|
|
24
31
|
export interface CostSummaryView {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/omp-stats",
|
|
4
|
-
"version": "17.0.
|
|
4
|
+
"version": "17.0.7",
|
|
5
5
|
"description": "Local observability dashboard for pi AI usage statistics",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
"fmt": "biome format --write ."
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@oh-my-pi/pi-ai": "17.0.
|
|
43
|
-
"@oh-my-pi/pi-catalog": "17.0.
|
|
44
|
-
"@oh-my-pi/pi-utils": "17.0.
|
|
42
|
+
"@oh-my-pi/pi-ai": "17.0.7",
|
|
43
|
+
"@oh-my-pi/pi-catalog": "17.0.7",
|
|
44
|
+
"@oh-my-pi/pi-utils": "17.0.7",
|
|
45
45
|
"@tailwindcss/node": "^4.3.2",
|
|
46
46
|
"chart.js": "^4.5.1",
|
|
47
47
|
"date-fns": "^4.4.0",
|
|
@@ -14,6 +14,18 @@ import type {
|
|
|
14
14
|
/** Fixed display order for the agent-token-share breakdown. */
|
|
15
15
|
const AGENT_TYPE_ORDER: AgentType[] = ["main", "subagent", "advisor"];
|
|
16
16
|
|
|
17
|
+
export interface ConversationTokenStats {
|
|
18
|
+
totalInputTokens: number;
|
|
19
|
+
totalOutputTokens: number;
|
|
20
|
+
totalCacheReadTokens: number;
|
|
21
|
+
totalCacheWriteTokens: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Sum every conversation-token bucket shown by the overview. */
|
|
25
|
+
export function sumConversationTokens(stats: ConversationTokenStats): number {
|
|
26
|
+
return stats.totalInputTokens + stats.totalOutputTokens + stats.totalCacheReadTokens + stats.totalCacheWriteTokens;
|
|
27
|
+
}
|
|
28
|
+
|
|
17
29
|
export interface AgentTokenSegment {
|
|
18
30
|
agentType: AgentType;
|
|
19
31
|
/** input + output + cache read + cache write — the displayed denominator. */
|
|
@@ -33,25 +45,21 @@ export interface AgentTokenShareView {
|
|
|
33
45
|
/**
|
|
34
46
|
* Build the "token usage by agent" breakdown: one segment per agent type that
|
|
35
47
|
* appears in the data, ordered main -> subagents -> advisor, each carrying its
|
|
36
|
-
* token total and share of the grand total. Token counts
|
|
37
|
-
*
|
|
38
|
-
* segment's share never disagrees with the count beside it.
|
|
48
|
+
* token total and share of the grand total. Token counts use the same four
|
|
49
|
+
* conversation-token buckets as the overview total so the two views reconcile.
|
|
39
50
|
*/
|
|
40
51
|
export function buildAgentTokenShare(stats: AgentTypeStats[]): AgentTokenShareView {
|
|
41
52
|
const byType = new Map<AgentType, AgentTypeStats>();
|
|
42
53
|
for (const stat of stats) byType.set(stat.agentType, stat);
|
|
43
54
|
|
|
44
|
-
const tokensOf = (stat: AgentTypeStats) =>
|
|
45
|
-
stat.totalInputTokens + stat.totalOutputTokens + stat.totalCacheReadTokens + stat.totalCacheWriteTokens;
|
|
46
|
-
|
|
47
55
|
const present = AGENT_TYPE_ORDER.map(type => byType.get(type)).filter(
|
|
48
56
|
(stat): stat is AgentTypeStats => stat !== undefined,
|
|
49
57
|
);
|
|
50
|
-
const totalTokens = present.reduce((sum, stat) => sum +
|
|
58
|
+
const totalTokens = present.reduce((sum, stat) => sum + sumConversationTokens(stat), 0);
|
|
51
59
|
const totalCost = present.reduce((sum, stat) => sum + stat.totalCost, 0);
|
|
52
60
|
|
|
53
61
|
const segments = present.map(stat => {
|
|
54
|
-
const tokens =
|
|
62
|
+
const tokens = sumConversationTokens(stat);
|
|
55
63
|
return {
|
|
56
64
|
agentType: stat.agentType,
|
|
57
65
|
tokens,
|
|
@@ -226,8 +226,8 @@ export function OverviewRoute({ active, range, refreshTrigger, onRequestClick }:
|
|
|
226
226
|
</AsyncBoundary>
|
|
227
227
|
|
|
228
228
|
<Panel
|
|
229
|
-
title="
|
|
230
|
-
subtitle="
|
|
229
|
+
title="Conversation Tokens by Agent"
|
|
230
|
+
subtitle="Uncached input + cache reads + cache writes + output, grouped by agent type"
|
|
231
231
|
>
|
|
232
232
|
<AsyncBoundary loading={overviewLoading} error={overviewError} data={overview}>
|
|
233
233
|
{overview && <AgentTokenShare stats={overview.byAgentType} />}
|
package/src/client/styles.css
CHANGED
|
@@ -581,17 +581,17 @@
|
|
|
581
581
|
|
|
582
582
|
.stats-metric-secondary-grid {
|
|
583
583
|
display: grid;
|
|
584
|
-
grid-template-columns: repeat(
|
|
584
|
+
grid-template-columns: repeat(8, 1fr);
|
|
585
585
|
gap: 12px;
|
|
586
586
|
}
|
|
587
587
|
|
|
588
|
-
@media (max-width:
|
|
588
|
+
@media (max-width: 1279px) {
|
|
589
589
|
.stats-metric-secondary-grid {
|
|
590
|
-
grid-template-columns: repeat(
|
|
590
|
+
grid-template-columns: repeat(4, 1fr);
|
|
591
591
|
}
|
|
592
592
|
}
|
|
593
593
|
|
|
594
|
-
@media (max-width:
|
|
594
|
+
@media (max-width: 767px) {
|
|
595
595
|
.stats-metric-secondary-grid {
|
|
596
596
|
grid-template-columns: repeat(2, 1fr);
|
|
597
597
|
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
formatPercent,
|
|
7
7
|
formatTokensPerSecond,
|
|
8
8
|
} from "../data/formatters";
|
|
9
|
+
import { sumConversationTokens } from "../data/view-models";
|
|
9
10
|
import type { AggregatedStats } from "../types";
|
|
10
11
|
|
|
11
12
|
export interface MetricClusterProps {
|
|
@@ -13,6 +14,8 @@ export interface MetricClusterProps {
|
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export function MetricCluster({ stats }: MetricClusterProps) {
|
|
17
|
+
const conversationTokens = sumConversationTokens(stats);
|
|
18
|
+
|
|
16
19
|
return (
|
|
17
20
|
<div className="stats-metric-cluster">
|
|
18
21
|
<div className="stats-metric-primary-grid">
|
|
@@ -37,14 +40,22 @@ export function MetricCluster({ stats }: MetricClusterProps) {
|
|
|
37
40
|
</div>
|
|
38
41
|
|
|
39
42
|
<div className="stats-metric-secondary-grid">
|
|
40
|
-
<div className="stats-metric-card secondary">
|
|
41
|
-
<div className="stats-metric-label">Input
|
|
43
|
+
<div className="stats-metric-card secondary" title="Conversation input not served from cache">
|
|
44
|
+
<div className="stats-metric-label">Uncached Input</div>
|
|
42
45
|
<div className="stats-metric-value">{formatCompact(stats.totalInputTokens)}</div>
|
|
43
46
|
</div>
|
|
47
|
+
<div className="stats-metric-card secondary" title="Conversation input read from the prompt cache">
|
|
48
|
+
<div className="stats-metric-label">Cache Read</div>
|
|
49
|
+
<div className="stats-metric-value">{formatCompact(stats.totalCacheReadTokens)}</div>
|
|
50
|
+
</div>
|
|
44
51
|
<div className="stats-metric-card secondary">
|
|
45
52
|
<div className="stats-metric-label">Output Tokens</div>
|
|
46
53
|
<div className="stats-metric-value">{formatCompact(stats.totalOutputTokens)}</div>
|
|
47
54
|
</div>
|
|
55
|
+
<div className="stats-metric-card secondary" title="Uncached input + cache reads + cache writes + output">
|
|
56
|
+
<div className="stats-metric-label">Conversation Total</div>
|
|
57
|
+
<div className="stats-metric-value">{formatCompact(conversationTokens)}</div>
|
|
58
|
+
</div>
|
|
48
59
|
<div className="stats-metric-card secondary">
|
|
49
60
|
<div className="stats-metric-label">Premium Requests</div>
|
|
50
61
|
<div className="stats-metric-value">{formatInteger(stats.totalPremiumRequests)}</div>
|