@linxiraos/pi-stats 1.0.9 → 1.1.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/CHANGELOG.md +2 -278
- package/LICENSE +22 -0
- package/README.md +4 -2
- package/package.json +91 -93
- package/src/aggregator.ts +16 -4
- package/src/client/app/NavRail.tsx +1 -1
- package/src/client/data/formatters.ts +13 -0
- package/src/client/data/view-models.ts +3 -0
- package/src/client/routes/CostsRoute.tsx +28 -10
- package/src/client/routes/ErrorsRoute.tsx +5 -5
- package/src/client/routes/ModelsRoute.tsx +3 -2
- package/src/client/routes/OverviewRoute.tsx +6 -6
- package/src/client/routes/ProjectsRoute.tsx +7 -5
- package/src/client/routes/ProvidersRoute.tsx +30 -5
- package/src/client/routes/RequestsRoute.tsx +5 -5
- package/src/client/routes/ToolsRoute.tsx +23 -11
- package/src/client/ui/MetricCluster.tsx +7 -3
- package/src/client/ui/RequestDrawer.tsx +3 -3
- package/src/db.ts +127 -35
- package/src/embedded-client.generated.txt +0 -1
- package/src/index.ts +43 -19
- package/src/port-conflict.ts +13 -8
- package/src/server.ts +26 -14
- package/src/shared-types.ts +14 -1
- package/src/usage-windows.ts +104 -28
- package/dist/client/index.css +0 -1
- package/dist/client/index.html +0 -24
- package/dist/client/index.js +0 -257
- package/dist/client/styles.css +0 -1692
- package/dist/types/aggregator.d.ts +0 -98
- package/dist/types/client/App.d.ts +0 -1
- package/dist/types/client/api.d.ts +0 -22
- package/dist/types/client/app/AppLayout.d.ts +0 -16
- package/dist/types/client/app/NavRail.d.ts +0 -7
- package/dist/types/client/app/RangeControl.d.ts +0 -7
- package/dist/types/client/app/SyncButton.d.ts +0 -14
- package/dist/types/client/app/ThemeToggle.d.ts +0 -1
- package/dist/types/client/app/TopBar.d.ts +0 -15
- package/dist/types/client/app/routes.d.ts +0 -12
- package/dist/types/client/components/AgentTokenShare.d.ts +0 -5
- package/dist/types/client/components/chart-shared.d.ts +0 -173
- package/dist/types/client/components/models-table-shared.d.ts +0 -175
- package/dist/types/client/components/range-meta.d.ts +0 -21
- package/dist/types/client/data/charts.d.ts +0 -1
- package/dist/types/client/data/formatters.d.ts +0 -8
- package/dist/types/client/data/useHashRoute.d.ts +0 -8
- package/dist/types/client/data/useResource.d.ts +0 -13
- package/dist/types/client/data/view-models.d.ts +0 -74
- package/dist/types/client/index.d.ts +0 -2
- package/dist/types/client/routes/BehaviorRoute.d.ts +0 -7
- package/dist/types/client/routes/CostsRoute.d.ts +0 -7
- package/dist/types/client/routes/ErrorsRoute.d.ts +0 -8
- package/dist/types/client/routes/GainRoute.d.ts +0 -7
- package/dist/types/client/routes/ModelsRoute.d.ts +0 -7
- package/dist/types/client/routes/OverviewRoute.d.ts +0 -8
- package/dist/types/client/routes/ProjectsRoute.d.ts +0 -7
- package/dist/types/client/routes/ProvidersRoute.d.ts +0 -7
- package/dist/types/client/routes/RequestsRoute.d.ts +0 -8
- package/dist/types/client/routes/ToolsRoute.d.ts +0 -7
- package/dist/types/client/routes/index.d.ts +0 -10
- package/dist/types/client/types.d.ts +0 -63
- package/dist/types/client/ui/AsyncBoundary.d.ts +0 -12
- package/dist/types/client/ui/DataTable.d.ts +0 -17
- package/dist/types/client/ui/EmptyState.d.ts +0 -7
- package/dist/types/client/ui/ErrorState.d.ts +0 -6
- package/dist/types/client/ui/JsonBlock.d.ts +0 -7
- package/dist/types/client/ui/MetricCluster.d.ts +0 -5
- package/dist/types/client/ui/Panel.d.ts +0 -7
- package/dist/types/client/ui/RequestDrawer.d.ts +0 -5
- package/dist/types/client/ui/SegmentedControl.d.ts +0 -12
- package/dist/types/client/ui/Skeleton.d.ts +0 -8
- package/dist/types/client/ui/StatusPill.d.ts +0 -7
- package/dist/types/client/ui/index.d.ts +0 -11
- package/dist/types/client/useSystemTheme.d.ts +0 -11
- package/dist/types/db.d.ts +0 -159
- package/dist/types/embedded-client.d.ts +0 -18
- package/dist/types/gain-aggregator.d.ts +0 -26
- package/dist/types/index.d.ts +0 -7
- package/dist/types/parser.d.ts +0 -53
- package/dist/types/port-conflict.d.ts +0 -14
- package/dist/types/server.d.ts +0 -12
- package/dist/types/shared-types.d.ts +0 -408
- package/dist/types/sync-worker.d.ts +0 -31
- package/dist/types/types.d.ts +0 -164
- package/dist/types/usage-windows.d.ts +0 -45
- package/dist/types/user-metrics.d.ts +0 -81
package/CHANGELOG.md
CHANGED
|
@@ -2,287 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
-
## [1.0
|
|
6
|
-
|
|
7
|
-
## [17.3.0] - 2026-08-13
|
|
8
|
-
|
|
9
|
-
### Added
|
|
10
|
-
|
|
11
|
-
- Added cost-weighted `cacheSavings` metric alongside `cacheRate`, accounting for cache-read discounts and write premiums against equivalent uncached prompt costs.
|
|
12
|
-
|
|
13
|
-
### Fixed
|
|
14
|
-
|
|
15
|
-
- Ensured the embedded dashboard archive is byte-reproducible by sorting entries and zeroing tar and gzip timestamps during compilation.
|
|
16
|
-
|
|
17
|
-
## [17.2.10] - 2026-08-06
|
|
5
|
+
## [1.1.0] - 2026-08-25
|
|
18
6
|
|
|
19
7
|
### Changed
|
|
20
8
|
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
## [17.2.9] - 2026-08-05
|
|
24
|
-
|
|
25
|
-
### Fixed
|
|
26
|
-
|
|
27
|
-
- Restricted the stats dashboard to IPv4 loopback and removed wildcard CORS access to its API ([#7633](https://github.com/can1357/oh-my-pi/issues/7633)).
|
|
28
|
-
|
|
29
|
-
## [17.2.4] - 2026-08-01
|
|
30
|
-
|
|
31
|
-
### Fixed
|
|
32
|
-
|
|
33
|
-
- Fixed provider usage window stats silently showing no data during SQLite contention by installing a five-second busy timeout on read-only agent database connections ([#7300](https://github.com/can1357/oh-my-pi/issues/7300)).
|
|
34
|
-
|
|
35
|
-
## [17.1.2] - 2026-07-24
|
|
36
|
-
|
|
37
|
-
### Added
|
|
38
|
-
|
|
39
|
-
- Added a Providers dashboard section: per-provider totals, stacked token/cost burn over time, peak-burn-hours histogram, subscription-window insights (windows burned, estimated tokens per window, peak concurrent utilization, ideal account count, exhaustion events), and latest window utilization per account — window analytics read the auth broker's `/v1/usage/history` when a broker is configured (falling back to the local agent DB), since broker deployments record usage history on the broker host
|
|
40
|
-
|
|
41
|
-
## [17.1.0] - 2026-07-24
|
|
42
|
-
|
|
43
|
-
### Fixed
|
|
44
|
-
|
|
45
|
-
- Fixed an issue where malformed persisted content blocks could abort stats ingestion for subsequent projects, and ensured pending full-session migrations are properly settled after successful backfills.
|
|
46
|
-
|
|
47
|
-
## [17.0.6] - 2026-07-20
|
|
48
|
-
|
|
49
|
-
### Changed
|
|
50
|
-
|
|
51
|
-
- Clarified overview token accounting by separating uncached input from cache reads and showing the conversation-token total used by the agent breakdown.
|
|
52
|
-
|
|
53
|
-
## [17.0.5] - 2026-07-18
|
|
54
|
-
|
|
55
|
-
### Fixed
|
|
56
|
-
|
|
57
|
-
- Fixed an EADDRINUSE error by properly reusing the live stats dashboard on the requested port and reclaiming stale listeners (#5970).
|
|
58
|
-
|
|
59
|
-
## [17.0.2] - 2026-07-17
|
|
60
|
-
|
|
61
|
-
### Fixed
|
|
62
|
-
|
|
63
|
-
- Fixed the Recent Errors list to honor the selected dashboard time range before returning the newest 50 failures.
|
|
64
|
-
|
|
65
|
-
## [16.4.7] - 2026-07-12
|
|
66
|
-
|
|
67
|
-
### Fixed
|
|
68
|
-
|
|
69
|
-
- Fixed a `SQLITE_CONSTRAINT_NOTNULL` crash (`messages.stop_reason`) aborting the entire session sync when a persisted assistant message lacks a `stopReason`. Malformed entries — missing stop reason, token counts, or message timestamp — are now coerced at the parser boundary, and entries with no usage or model attribution are skipped instead of failing the batch insert.
|
|
70
|
-
|
|
71
|
-
## [16.4.2] - 2026-07-10
|
|
72
|
-
|
|
73
|
-
### Fixed
|
|
74
|
-
|
|
75
|
-
- Fixed a crash during stats synchronization on legacy session entries that lack a cost breakdown by falling back to catalog pricing when available.
|
|
76
|
-
|
|
77
|
-
## [16.3.9] - 2026-07-06
|
|
78
|
-
|
|
79
|
-
### Changed
|
|
80
|
-
|
|
81
|
-
- Refined behavior metrics to significantly reduce false positives in profanity, yelling, and anguish detection by excluding technical terms (e.g., "dummy", "trash", "garbage"), neutral punctuation (e.g., dot runs), and single-word capitalization (e.g., filenames or environment variables).
|
|
82
|
-
- Re-categorized frustration interjections (such as "ugh", "argh", and "grr") from profanity to anguish.
|
|
83
|
-
- Improved negation and blame detection to exclude determiners (e.g., "no auto start") and compounds (e.g., "no-op") while adding support for phrases like "why did you" and "makes no sense".
|
|
84
|
-
- Added sad emoticons as a signal for anguish while excluding code-like patterns.
|
|
85
|
-
- Triggered a one-time automatic re-ingestion of sessions on the next database sync to apply the updated metrics.
|
|
86
|
-
|
|
87
|
-
## [16.3.7] - 2026-07-05
|
|
88
|
-
|
|
89
|
-
### Changed
|
|
90
|
-
|
|
91
|
-
- Optimized session-entry lookup and file reading performance by caching file metadata to avoid repeated full-file scans.
|
|
92
|
-
|
|
93
|
-
## [16.3.1] - 2026-07-02
|
|
94
|
-
|
|
95
|
-
### Added
|
|
96
|
-
|
|
97
|
-
- Added a Tools tab to the `omp stats` dashboard (`/#/tools`): per-tool call counts, error rates, result/argument payload sizes, per-model breakdown, and a stacked calls-over-time chart. Token and cost columns attribute each invoking turn's real provider usage evenly across that turn's tool calls. Existing databases re-parse sessions once on the next sync to backfill historical tool calls.
|
|
98
|
-
|
|
99
|
-
## [16.2.7] - 2026-06-30
|
|
100
|
-
|
|
101
|
-
### Fixed
|
|
102
|
-
|
|
103
|
-
- Improved premium request calculation accuracy by correctly accounting for specific model families.
|
|
104
|
-
|
|
105
|
-
## [16.2.6] - 2026-06-29
|
|
106
|
-
|
|
107
|
-
### Fixed
|
|
108
|
-
|
|
109
|
-
- Fixed application crashes and Bun aborts on macOS and when parsing large stats session files, including during `omp --smoke-test` runs, by utilizing a more resilient serial parser and lenient line scanner.
|
|
110
|
-
|
|
111
|
-
## [16.2.3] - 2026-06-28
|
|
112
|
-
|
|
113
|
-
### Added
|
|
114
|
-
|
|
115
|
-
- Support for parsing named advisor transcripts using the `__advisor.<slug>.jsonl` naming convention.
|
|
116
|
-
|
|
117
|
-
## [16.2.0] - 2026-06-27
|
|
118
|
-
|
|
119
|
-
### Added
|
|
120
|
-
|
|
121
|
-
- Added a Gain tab to the `omp stats` dashboard (`/#/gain`) to display snapcompact token-savings with project scoping from synced session folders.
|
|
122
|
-
|
|
123
|
-
## [16.1.17] - 2026-06-24
|
|
124
|
-
|
|
125
|
-
### Fixed
|
|
126
|
-
|
|
127
|
-
- Stats sync counted the same provider request multiple times when a forked or branched session file copied the parent's entries verbatim. Inserts now skip rows whose `(entry_id, timestamp)` already exists under a different `session_file`, and a one-shot migration on the next `omp stats` run collapses any pre-existing duplicates ([#3370](https://github.com/can1357/oh-my-pi/issues/3370)).
|
|
128
|
-
|
|
129
|
-
## [16.1.15] - 2026-06-22
|
|
130
|
-
|
|
131
|
-
### Added
|
|
132
|
-
|
|
133
|
-
- Added token usage breakdown by agent type (Main, Subagents, Advisor) to the overview dashboard
|
|
134
|
-
|
|
135
|
-
## [16.0.10] - 2026-06-18
|
|
136
|
-
|
|
137
|
-
### Changed
|
|
138
|
-
|
|
139
|
-
- Updated description of moderated content categories to use more inclusive terminology
|
|
140
|
-
|
|
141
|
-
### Fixed
|
|
142
|
-
|
|
143
|
-
- Wide data tables (Requests, Errors, Overview, Projects) overflowed the page horizontally at narrow-desktop widths (768-1023px): the `.stats-table-desktop-only` wrapper used for mobile-card tables lacked the `overflow-x: auto` containment that `.stats-table-container` already has. They now scroll within their own bounds instead of spilling the page body.
|
|
144
|
-
|
|
145
|
-
## [16.0.5] - 2026-06-17
|
|
146
|
-
|
|
147
|
-
### Added
|
|
148
|
-
|
|
149
|
-
- New Projects view summarizing usage, cost, and reliability per project folder (backed by the existing `/api/stats/folders` endpoint).
|
|
150
|
-
- System-aware light/dark theme toggle — follows the OS by default, and an explicit choice persists across reloads.
|
|
151
|
-
|
|
152
|
-
### Changed
|
|
153
|
-
|
|
154
|
-
- Redesigned the local stats dashboard with an OMP-themed product shell, dedicated per-section views, accessible loading/empty/error states, and flicker-free navigation between screens and time ranges.
|
|
155
|
-
|
|
156
|
-
### Fixed
|
|
157
|
-
|
|
158
|
-
- The 1h time-range chart rendered an empty/single-point line; it now buckets at 5-minute granularity for a real trend.
|
|
159
|
-
|
|
160
|
-
## [15.13.3] - 2026-06-15
|
|
161
|
-
|
|
162
|
-
### Changed
|
|
163
|
-
|
|
164
|
-
- Renamed `__omp_stats_sync_worker` to `__omp_worker_stats_sync`.
|
|
165
|
-
|
|
166
|
-
## [15.13.1] - 2026-06-15
|
|
167
|
-
|
|
168
|
-
### Fixed
|
|
169
|
-
|
|
170
|
-
- Dropped `git` from the profanity list so normal repository mentions no longer count as profanity
|
|
171
|
-
|
|
172
|
-
## [15.12.4] - 2026-06-13
|
|
173
|
-
|
|
174
|
-
### Fixed
|
|
175
|
-
|
|
176
|
-
- Fixed the stats dashboard's SQLite init never setting `PRAGMA busy_timeout`, so a concurrent `omp` startup hitting WAL recovery could crash `initDb()` with `SQLITE_BUSY` instead of waiting through it. The busy handler is now installed before `PRAGMA journal_mode=WAL` ([#2421](https://github.com/can1357/oh-my-pi/issues/2421)).
|
|
177
|
-
|
|
178
|
-
## [15.11.0] - 2026-06-10
|
|
179
|
-
|
|
180
|
-
### Added
|
|
181
|
-
|
|
182
|
-
- Added support for prebuilt npm bundle mode via `PI_BUNDLED`, allowing the stats server to use an embedded dashboard bundle in packaged CLI distributions
|
|
183
|
-
|
|
184
|
-
### Fixed
|
|
185
|
-
|
|
186
|
-
- Fixed handling of legacy `embedded-client.generated.txt` placeholder content so it is treated as missing archive instead of being decoded into invalid bytes
|
|
187
|
-
- Fixed ENOENT handling while scanning dashboard source/build directories so missing `client/` or `dist/client` trees no longer crash startup
|
|
188
|
-
|
|
189
|
-
## [15.10.11] - 2026-06-10
|
|
190
|
-
|
|
191
|
-
### Changed
|
|
192
|
-
|
|
193
|
-
- Bundled-model lookups (`getBundledModel`, `GeneratedProvider`) now import from the new `@linxiraos/pi-catalog` package instead of the `@linxiraos/pi-ai` barrel, which no longer re-exports catalog values
|
|
194
|
-
- The session-sync worker re-enters the host CLI entry (`workerHostEntry()` + `__omp_stats_sync_worker` argv selector) when running inside omp — source, npm bundle, or compiled binary — and keeps loading its own `sync-worker.ts` module directly for standalone `omp-stats`, bun test, and SDK hosts
|
|
195
|
-
|
|
196
|
-
## [15.1.6] - 2026-05-19
|
|
197
|
-
|
|
198
|
-
### Fixed
|
|
199
|
-
|
|
200
|
-
- Fixed `omp stats` crashing on first session sync in published `omp-{linux,darwin,windows}-*` binaries with `BuildMessage: ModuleNotFound resolving "./packages/stats/src/sync-worker.ts"`; the release build script now lists the stats sync, browser tab, and JS eval workers as explicit `--compile` entrypoints so Bun emits them into bunfs, matching the dev build script and the AGENTS.md worker spawn contract. ([#1150](https://github.com/can1357/oh-my-pi/issues/1150))
|
|
201
|
-
|
|
202
|
-
## [15.1.0] - 2026-05-15
|
|
203
|
-
|
|
204
|
-
### Fixed
|
|
205
|
-
|
|
206
|
-
- Fixed incremental `parseSessionFile(path, fromOffset)` losing the active service tier when resuming past a `service_tier_change` entry, so priority OpenAI replies appended after the offset are now credited with `premiumRequests: 1` (regression introduced by 13f59162e which stopped folding priority-tier into per-message premium counts)
|
|
207
|
-
|
|
208
|
-
## [15.0.1] - 2026-05-14
|
|
209
|
-
|
|
210
|
-
### Breaking Changes
|
|
211
|
-
|
|
212
|
-
- Raised the minimum required Bun version to >=1.3.14 in package metadata
|
|
213
|
-
|
|
214
|
-
### Changed
|
|
215
|
-
|
|
216
|
-
- Changed the "Premium Reqs" dashboard card to also include OpenAI priority service-tier requests (`serviceTier: "priority"`), counting each as 1 premium request alongside GitHub Copilot premium calls. Pre-existing sessions are backfilled on the next `omp stats` run: a one-shot `premium_requests_priority_v1` sentinel wipes `file_offsets` so every session re-parses, and `insertMessageStats` now `UPSERT`s `premium_requests` (other columns untouched) using the `service_tier_change` entries already in the session log to retroactively credit priority traffic.
|
|
217
|
-
|
|
218
|
-
## [14.9.9] - 2026-05-12
|
|
219
|
-
|
|
220
|
-
### Added
|
|
221
|
-
|
|
222
|
-
- Added separate input-token and output-token totals to the overview dashboard cards.
|
|
223
|
-
|
|
224
|
-
### Fixed
|
|
225
|
-
|
|
226
|
-
- Fixed `omp stats` in compiled binaries by using the serial sync path instead of spawning a raw file-asset worker that cannot import bundled parser code.
|
|
227
|
-
- Fixed behavior backfills after failed compiled-binary sync attempts by marking the backfill sentinel only after a successful full sync.
|
|
228
|
-
|
|
229
|
-
## [14.9.7] - 2026-05-12
|
|
230
|
-
|
|
231
|
-
### Breaking Changes
|
|
232
|
-
|
|
233
|
-
- Broke backward compatibility of behavior stats fields by replacing `yellingSentences`/`dramaRuns` with `yelling`/`anguish` and adding `negation`, `repetition`, `blame` in query result types and persisted `user_messages` schema
|
|
234
|
-
|
|
235
|
-
### Added
|
|
236
|
-
|
|
237
|
-
- Added `SyncOptions` to `syncAllSessions` with `onProgress` and `workers` to optionally show per-file sync progress and tune parser concurrency
|
|
238
|
-
- Added new frustration behavior metrics (`negation`, `repetition`, `blame`) plus a `frustration` aggregate in behavior charts, model tables, and summary cards
|
|
239
|
-
|
|
240
|
-
### Changed
|
|
241
|
-
|
|
242
|
-
- Changed sync ingestion to parse session files through a worker pool while applying parsed results and database writes on the main thread
|
|
243
|
-
- Changed behavior analysis to strip code blocks, XML/URLs, quoted lines, and placeholders before scoring and to suppress signals on long structured messages
|
|
244
|
-
- Changed dashboard metrics labels and totals to the new signal names, including replacing the old three-signal totals with `yelling`, `profanity`, `anguish`, and `frustration`
|
|
245
|
-
- Changed sync output to print a live terminal progress indicator while processing session files
|
|
246
|
-
|
|
247
|
-
### Fixed
|
|
248
|
-
|
|
249
|
-
- Fixed user-message attribution so assistant model/provider links are backfilled during incremental sync instead of being left unknown
|
|
250
|
-
- Fixed word-boundary regex handling in profanity detection so matching now works as intended in normal prose
|
|
251
|
-
|
|
252
|
-
## [14.9.5] - 2026-05-12
|
|
253
|
-
|
|
254
|
-
### Added
|
|
255
|
-
|
|
256
|
-
- Added time range selection options (1h, 24h, 7d, 30d, 90d, All) to the dashboard header and bound them to reloading statistics for the selected window
|
|
257
|
-
- Added a **Behavior** dashboard page that tracks user yelling (CAPS), profanity, and dramatic punctuation (`!!!` / `???`) per day, with by-model comparisons mirroring the cost page
|
|
258
|
-
- Added a per-model behavior table to the **Behavior** page mirroring the Models table: sortable rows of CAPS / profanity / drama hits per model with sparkline trend and an expandable per-model breakdown chart
|
|
259
|
-
- Added optional `range` query parameter support on stats endpoints to retrieve metrics scoped to a requested time window
|
|
260
|
-
|
|
261
|
-
### Changed
|
|
262
|
-
|
|
263
|
-
- Changed the Costs dashboard summary to report totals, average per day, and top model for the selected time range instead of a fixed 30-day window and removed the previous-30-day trend comparison
|
|
264
|
-
- Changed behavior metrics ingestion to compute yelling from user message sentence-level uppercase ratios, filtering out short uppercase fragments so the behavior data is attributed to messages more accurately
|
|
265
|
-
- Removed per-chart 14/30/90 day pickers on Costs and Behavior pages so every page obeys the single time-range selector in the header
|
|
266
|
-
- Changed dashboard and stats queries to return data from the selected time window instead of always using all-time aggregates
|
|
267
|
-
- Changed the default displayed range in the UI/API to last 24h
|
|
268
|
-
- Added support for returning all data when `range=all` is requested
|
|
269
|
-
|
|
270
|
-
### Fixed
|
|
271
|
-
|
|
272
|
-
- Fixed handling of unknown `range` values by falling back to the last 24h instead of returning unscoped data
|
|
273
|
-
- Fixed `omp stats` failing to build the client on globally-installed installs by promoting `tailwindcss` from `devDependencies` to `dependencies` (the client build runs at runtime)
|
|
274
|
-
|
|
275
|
-
## [14.5.4] - 2026-04-28
|
|
276
|
-
|
|
277
|
-
### Fixed
|
|
278
|
-
|
|
279
|
-
- Fixed GPT cost reporting by deriving missing OpenAI Codex costs from the model catalog and backfilling existing zero-cost rows.
|
|
280
|
-
|
|
281
|
-
## [13.6.0] - 2026-03-03
|
|
282
|
-
|
|
283
|
-
### Fixed
|
|
284
|
-
|
|
285
|
-
- Include subtask session files in usage stats ([#250](https://github.com/can1357/oh-my-pi/issues/250))
|
|
9
|
+
- 同步上游 OMP v18.0.3 / v18.0.4(内部运行时与构建改进,无独立用户可见变更)。
|
|
286
10
|
|
|
287
11
|
## [1.0.0] - 2026-08-13
|
|
288
12
|
|
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Can Bölük
|
|
4
|
+
Copyright (c) 2026 Stencil Labs, Inc.
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -17,10 +17,12 @@ Local observability dashboard for AI usage statistics.
|
|
|
17
17
|
| Cache Rate | `cache_read / (input + cache_read) * 100` |
|
|
18
18
|
| Cache Savings | `(uncached prompt cost - actual prompt cost) / uncached prompt cost * 100` |
|
|
19
19
|
| Error Rate | `count(stopReason=error) / total_calls * 100` |
|
|
20
|
-
|
|
|
20
|
+
| API-equivalent estimate | Sum of token usage priced with the matching public API rate card |
|
|
21
21
|
| Avg Latency | Mean of `duration` |
|
|
22
22
|
| TTFT | Mean of `ttft` (time to first token) |
|
|
23
23
|
|
|
24
|
+
Subscription-backed models use matching public API prices when an exact public model exists; these values estimate API-equivalent usage rather than the user's bill. Subscription-only models without a public price are reported as N/A and excluded from dollar totals.
|
|
25
|
+
|
|
24
26
|
## Usage
|
|
25
27
|
|
|
26
28
|
### Via CLI
|
|
@@ -72,7 +74,7 @@ console.log(stats.byModel[0].avgTokensPerSecond);
|
|
|
72
74
|
|
|
73
75
|
The web dashboard provides:
|
|
74
76
|
|
|
75
|
-
- Overall metrics cards (requests,
|
|
77
|
+
- Overall metrics cards (requests, API-equivalent estimate, cache rate, cache savings, error rate, duration, tokens/s)
|
|
76
78
|
- Time series chart showing requests and errors over time
|
|
77
79
|
- Per-model breakdown table
|
|
78
80
|
- Per-folder breakdown table
|
package/package.json
CHANGED
|
@@ -1,94 +1,92 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
}
|
|
2
|
+
"type": "module",
|
|
3
|
+
"name": "@linxiraos/pi-stats",
|
|
4
|
+
"version": "1.1.0",
|
|
5
|
+
"description": "Local observability dashboard for pi AI usage statistics",
|
|
6
|
+
"homepage": "https://linxira-os.github.io/zeta/",
|
|
7
|
+
"author": "Can Boluk",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/Linxira-OS/linxira-zeta.git",
|
|
12
|
+
"directory": "packages/stats"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/Linxira-OS/linxira-zeta/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"ai",
|
|
19
|
+
"observability",
|
|
20
|
+
"metrics",
|
|
21
|
+
"dashboard",
|
|
22
|
+
"llm",
|
|
23
|
+
"statistics"
|
|
24
|
+
],
|
|
25
|
+
"main": "./src/index.ts",
|
|
26
|
+
"types": "./src/index.ts",
|
|
27
|
+
"bin": {
|
|
28
|
+
"omp-stats": "./src/index.ts"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"gen:stats": "bun scripts/generate-client-bundle.ts --generate",
|
|
32
|
+
"gen:stats:reset": "bun scripts/generate-client-bundle.ts --reset",
|
|
33
|
+
"build": "bun run build.ts",
|
|
34
|
+
"dev": "bun run src/index.ts",
|
|
35
|
+
"check": "biome check . && bun run check:types",
|
|
36
|
+
"check:types": "tsgo -p tsconfig.json --noEmit && tsgo -p tsconfig.client.json --noEmit",
|
|
37
|
+
"lint": "biome lint .",
|
|
38
|
+
"fix": "biome check --write --unsafe .",
|
|
39
|
+
"fmt": "biome format --write ."
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@linxiraos/pi-ai": "catalog:",
|
|
43
|
+
"@linxiraos/pi-catalog": "catalog:",
|
|
44
|
+
"@linxiraos/pi-utils": "catalog:",
|
|
45
|
+
"@tailwindcss/node": "catalog:",
|
|
46
|
+
"chart.js": "catalog:",
|
|
47
|
+
"lucide-react": "catalog:",
|
|
48
|
+
"react": "catalog:",
|
|
49
|
+
"react-chartjs-2": "catalog:",
|
|
50
|
+
"react-dom": "catalog:",
|
|
51
|
+
"tailwindcss": "catalog:"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@types/bun": "catalog:",
|
|
55
|
+
"@types/react": "catalog:",
|
|
56
|
+
"@types/react-dom": "catalog:",
|
|
57
|
+
"postcss": "catalog:"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"bun": ">=1.3.14"
|
|
61
|
+
},
|
|
62
|
+
"files": [
|
|
63
|
+
"src",
|
|
64
|
+
"build.ts",
|
|
65
|
+
"tailwind.config.js",
|
|
66
|
+
"README.md",
|
|
67
|
+
"CHANGELOG.md"
|
|
68
|
+
],
|
|
69
|
+
"exports": {
|
|
70
|
+
".": {
|
|
71
|
+
"types": "./src/index.ts",
|
|
72
|
+
"import": "./src/index.ts"
|
|
73
|
+
},
|
|
74
|
+
"./*": {
|
|
75
|
+
"types": "./src/*.ts",
|
|
76
|
+
"import": "./src/*.ts"
|
|
77
|
+
},
|
|
78
|
+
"./client": {
|
|
79
|
+
"types": "./src/client/index.tsx",
|
|
80
|
+
"import": "./src/client/index.tsx"
|
|
81
|
+
},
|
|
82
|
+
"./client/*": {
|
|
83
|
+
"types": "./src/client/*.ts",
|
|
84
|
+
"import": "./src/client/*.ts"
|
|
85
|
+
},
|
|
86
|
+
"./client/components/*": {
|
|
87
|
+
"types": "./src/client/components/*.ts",
|
|
88
|
+
"import": "./src/client/components/*.ts"
|
|
89
|
+
},
|
|
90
|
+
"./*.js": "./src/*.ts"
|
|
91
|
+
}
|
|
92
|
+
}
|
package/src/aggregator.ts
CHANGED
|
@@ -42,12 +42,13 @@ import type { SyncWorkerRequest, SyncWorkerResponse } from "./sync-worker";
|
|
|
42
42
|
import type {
|
|
43
43
|
BehaviorDashboardStats,
|
|
44
44
|
DashboardStats,
|
|
45
|
+
FolderStats,
|
|
45
46
|
MessageStats,
|
|
46
47
|
ProviderDashboardStats,
|
|
47
48
|
RequestDetails,
|
|
48
49
|
ToolDashboardStats,
|
|
49
50
|
} from "./types";
|
|
50
|
-
import { computeUsageWindowStats,
|
|
51
|
+
import { computeUsageWindowStats, fetchUsageData } from "./usage-windows";
|
|
51
52
|
|
|
52
53
|
/**
|
|
53
54
|
* Apply a freshly parsed result to the database. Runs entirely on the
|
|
@@ -455,6 +456,13 @@ export async function getCostDashboardStats(range?: string | null): Promise<Pick
|
|
|
455
456
|
costSeries: getCostTimeSeries(costSeriesDays, cutoff),
|
|
456
457
|
};
|
|
457
458
|
}
|
|
459
|
+
|
|
460
|
+
export async function getFolderStats(range?: string | null): Promise<FolderStats[]> {
|
|
461
|
+
await initDb();
|
|
462
|
+
const { cutoff } = getTimeRangeConfig(range);
|
|
463
|
+
return getStatsByFolder(cutoff ?? undefined);
|
|
464
|
+
}
|
|
465
|
+
|
|
458
466
|
export async function getRecentRequests(limit?: number): Promise<MessageStats[]> {
|
|
459
467
|
await initDb();
|
|
460
468
|
return dbGetRecentRequests(limit);
|
|
@@ -521,14 +529,18 @@ export async function getToolDashboardStats(range?: string | null): Promise<Tool
|
|
|
521
529
|
* Get the providers dashboard payload: per-provider totals, peak-burn-hours
|
|
522
530
|
* histogram, provider token time series, and subscription-window analytics
|
|
523
531
|
* (utilization series + insights) derived from recorded usage-limit snapshots.
|
|
532
|
+
*
|
|
533
|
+
* Window token estimates use broker-held fleet token burn when a broker is
|
|
534
|
+
* configured — the window fractions cover every install sharing the broker's
|
|
535
|
+
* credentials, so dividing them into local-only tokens would undercount.
|
|
524
536
|
*/
|
|
525
537
|
export async function getProviderDashboardStats(range?: string | null): Promise<ProviderDashboardStats> {
|
|
526
538
|
await initDb();
|
|
527
539
|
const { modelSeriesDays, modelSeriesBucketMs, cutoff } = getTimeRangeConfig(range);
|
|
528
540
|
const providers = getStatsByProvider(cutoff ?? undefined);
|
|
529
|
-
const
|
|
530
|
-
const
|
|
531
|
-
const { usageSeries, windowInsights } = computeUsageWindowStats(
|
|
541
|
+
const usage = await fetchUsageData(cutoff ?? 0);
|
|
542
|
+
const tokensByProvider = usage.fleetTokensByProvider ?? new Map(providers.map(p => [p.provider, p.totalTokens]));
|
|
543
|
+
const { usageSeries, windowInsights } = computeUsageWindowStats(usage.rows, tokensByProvider);
|
|
532
544
|
return {
|
|
533
545
|
providers,
|
|
534
546
|
hourly: getProviderHourlyBurn(cutoff ?? undefined),
|
|
@@ -37,7 +37,7 @@ export function NavRail({ activeSection, onSectionChange, className = "" }: NavR
|
|
|
37
37
|
</nav>
|
|
38
38
|
|
|
39
39
|
<div className="stats-nav-rail-footer">
|
|
40
|
-
<span className="stats-version-tag">
|
|
40
|
+
<span className="stats-version-tag">Zeta Stats</span>
|
|
41
41
|
</div>
|
|
42
42
|
</aside>
|
|
43
43
|
);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { formatDistanceToNow } from "@linxiraos/pi-utils/dates";
|
|
2
|
+
import type { MessageStats } from "../types";
|
|
2
3
|
|
|
3
4
|
export function formatInteger(value: number): string {
|
|
4
5
|
return value.toLocaleString();
|
|
@@ -17,6 +18,18 @@ export function formatCost(value: number, digits?: number): string {
|
|
|
17
18
|
})}`;
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
/** Format an API-equivalent estimate, using N/A when all usage is unpriced. */
|
|
22
|
+
export function formatEstimatedCost(value: number, unpricedRequests: number, digits?: number): string {
|
|
23
|
+
return value === 0 && unpricedRequests > 0 ? "N/A" : formatCost(value, digits);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Format one request's cost, distinguishing unpriced SuperGrok usage from free usage. */
|
|
27
|
+
export function formatMessageCost(message: Pick<MessageStats, "provider" | "usage">, digits?: number): string {
|
|
28
|
+
const unpricedRequests =
|
|
29
|
+
message.provider === "xai-oauth" && message.usage.totalTokens > 0 && message.usage.cost.total === 0 ? 1 : 0;
|
|
30
|
+
return formatEstimatedCost(message.usage.cost.total, unpricedRequests, digits);
|
|
31
|
+
}
|
|
32
|
+
|
|
20
33
|
export function formatPercent(value: number, digits = 1): string {
|
|
21
34
|
return `${(value * 100).toFixed(digits)}%`;
|
|
22
35
|
}
|
|
@@ -74,6 +74,7 @@ export function buildAgentTokenShare(stats: AgentTypeStats[]): AgentTokenShareVi
|
|
|
74
74
|
|
|
75
75
|
export interface CostSummaryView {
|
|
76
76
|
totalCost: number;
|
|
77
|
+
unpricedRequests: number;
|
|
77
78
|
avgDailyCost: number;
|
|
78
79
|
topModelName: string;
|
|
79
80
|
topModelCost: number;
|
|
@@ -111,6 +112,7 @@ export interface FolderRowView extends FolderStats {
|
|
|
111
112
|
|
|
112
113
|
export function buildCostSummary(costSeries: CostTimeSeriesPoint[]): CostSummaryView {
|
|
113
114
|
const totalCost = costSeries.reduce((sum, p) => sum + p.cost, 0);
|
|
115
|
+
const unpricedRequests = costSeries.reduce((sum, point) => sum + point.unpricedRequests, 0);
|
|
114
116
|
const dayBuckets = new Set(costSeries.map(p => p.timestamp)).size;
|
|
115
117
|
const avgDailyCost = dayBuckets > 0 ? totalCost / dayBuckets : 0;
|
|
116
118
|
|
|
@@ -130,6 +132,7 @@ export function buildCostSummary(costSeries: CostTimeSeriesPoint[]): CostSummary
|
|
|
130
132
|
|
|
131
133
|
return {
|
|
132
134
|
totalCost,
|
|
135
|
+
unpricedRequests,
|
|
133
136
|
avgDailyCost,
|
|
134
137
|
topModelName,
|
|
135
138
|
topModelCost,
|