@linxiraos/pi-stats 1.1.26 → 1.2.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 +12 -5
- package/build.ts +4 -0
- package/dist/client/favicon.ico +0 -0
- package/dist/client/index.css +1 -1
- package/dist/client/index.html +1 -0
- package/dist/client/index.js +96 -96
- package/dist/types/aggregator.d.ts +4 -1
- package/dist/types/client/api.d.ts +5 -1
- package/dist/types/client/app/nav.d.ts +5 -2
- package/dist/types/client/data/formatters.d.ts +7 -2
- package/dist/types/client/data/live.d.ts +16 -11
- package/dist/types/client/data/query-store.d.ts +39 -0
- package/dist/types/client/data/query.d.ts +10 -5
- package/dist/types/client/data/range.d.ts +4 -3
- package/dist/types/client/i18n/format.d.ts +9 -0
- package/dist/types/client/i18n/index.d.ts +18 -0
- package/dist/types/client/i18n/messages/charts.d.ts +8 -0
- package/dist/types/client/i18n/messages/common.d.ts +153 -0
- package/dist/types/client/i18n/messages/costs.d.ts +92 -0
- package/dist/types/client/i18n/messages/en.d.ts +1255 -0
- package/dist/types/client/i18n/messages/errors.d.ts +78 -0
- package/dist/types/client/i18n/messages/frustration.d.ts +191 -0
- package/dist/types/client/i18n/messages/gain.d.ts +54 -0
- package/dist/types/client/i18n/messages/models.d.ts +94 -0
- package/dist/types/client/i18n/messages/nav.d.ts +46 -0
- package/dist/types/client/i18n/messages/overview.d.ts +80 -0
- package/dist/types/client/i18n/messages/projects.d.ts +84 -0
- package/dist/types/client/i18n/messages/providers.d.ts +142 -0
- package/dist/types/client/i18n/messages/requests.d.ts +72 -0
- package/dist/types/client/i18n/messages/tools.d.ts +119 -0
- package/dist/types/client/i18n/messages/traces.d.ts +144 -0
- package/dist/types/client/i18n/messages/ui.d.ts +44 -0
- package/dist/types/client/i18n/messages/zh-CN.d.ts +13 -0
- package/dist/types/client/i18n/types.d.ts +15 -0
- package/dist/types/client/traces/Minimap.d.ts +2 -0
- package/dist/types/client/traces/TimelineCanvas.d.ts +29 -8
- package/dist/types/client/traces/TranscriptList.d.ts +3 -1
- package/dist/types/db.d.ts +14 -21
- package/dist/types/embedded-client.d.ts +5 -0
- package/dist/types/frustration.d.ts +18 -9
- package/dist/types/live.d.ts +5 -3
- package/dist/types/locale.d.ts +16 -0
- package/dist/types/parser.d.ts +0 -17
- package/dist/types/rollup.d.ts +9 -1
- package/dist/types/server.d.ts +6 -0
- package/dist/types/shared-types.d.ts +7 -0
- package/dist/types/trace.d.ts +18 -6
- package/dist/types/types.d.ts +13 -1
- package/dist/types/user-metrics.d.ts +23 -1
- package/package.json +5 -5
- package/src/aggregator.ts +31 -11
- package/src/client/api.ts +40 -5
- package/src/client/app/LiveChip.tsx +14 -13
- package/src/client/app/Shell.tsx +19 -13
- package/src/client/app/ThemeToggle.tsx +4 -3
- package/src/client/app/nav.ts +19 -16
- package/src/client/data/formatters.ts +80 -13
- package/src/client/data/live.tsx +85 -45
- package/src/client/data/query-store.ts +108 -0
- package/src/client/data/query.ts +47 -56
- package/src/client/data/range.ts +34 -14
- package/src/client/data/series.ts +7 -1
- package/src/client/favicon.ico +0 -0
- package/src/client/i18n/format.ts +28 -0
- package/src/client/i18n/index.ts +53 -0
- package/src/client/i18n/messages/charts.ts +8 -0
- package/src/client/i18n/messages/common.ts +157 -0
- package/src/client/i18n/messages/costs.ts +104 -0
- package/src/client/i18n/messages/en.ts +40 -0
- package/src/client/i18n/messages/errors.ts +80 -0
- package/src/client/i18n/messages/frustration.ts +198 -0
- package/src/client/i18n/messages/gain.ts +54 -0
- package/src/client/i18n/messages/models.ts +94 -0
- package/src/client/i18n/messages/nav.ts +46 -0
- package/src/client/i18n/messages/overview.ts +90 -0
- package/src/client/i18n/messages/projects.ts +84 -0
- package/src/client/i18n/messages/providers.ts +165 -0
- package/src/client/i18n/messages/requests.ts +73 -0
- package/src/client/i18n/messages/tools.ts +120 -0
- package/src/client/i18n/messages/traces.ts +160 -0
- package/src/client/i18n/messages/ui.ts +46 -0
- package/src/client/i18n/messages/zh-CN.ts +43 -0
- package/src/client/i18n/types.ts +19 -0
- package/src/client/index.tsx +4 -0
- package/src/client/routes/CostsRoute.tsx +61 -48
- package/src/client/routes/ErrorsRoute.tsx +71 -47
- package/src/client/routes/FrustrationRoute.tsx +131 -116
- package/src/client/routes/GainRoute.tsx +42 -30
- package/src/client/routes/ModelsRoute.tsx +90 -73
- package/src/client/routes/OverviewRoute.tsx +109 -63
- package/src/client/routes/ProjectsRoute.tsx +73 -46
- package/src/client/routes/ProvidersRoute.tsx +151 -114
- package/src/client/routes/RequestsRoute.tsx +69 -46
- package/src/client/routes/ToolsRoute.tsx +108 -94
- package/src/client/routes/TracesRoute.tsx +25 -23
- package/src/client/styles.css +5 -2
- package/src/client/traces/AggregatesPanel.tsx +19 -8
- package/src/client/traces/Minimap.tsx +65 -27
- package/src/client/traces/SpanDrawer.tsx +46 -21
- package/src/client/traces/SummaryStrip.tsx +27 -11
- package/src/client/traces/TimelineCanvas.tsx +245 -116
- package/src/client/traces/TraceView.tsx +51 -36
- package/src/client/traces/TranscriptList.tsx +20 -11
- package/src/client/traces/traces.css +26 -0
- package/src/client/ui/JsonBlock.tsx +3 -2
- package/src/client/ui/Modal.tsx +3 -2
- package/src/client/ui/RequestDrawer.tsx +33 -30
- package/src/client/ui/SearchInput.tsx +2 -1
- package/src/client/ui/States.tsx +3 -2
- package/src/client/ui/Table.tsx +7 -3
- package/src/db.ts +150 -135
- package/src/embedded-client.ts +9 -0
- package/src/frustration.ts +9 -30
- package/src/index.ts +2 -1
- package/src/live.ts +36 -11
- package/src/locale.ts +29 -0
- package/src/parser.ts +37 -72
- package/src/port-conflict.ts +1 -1
- package/src/prompts/judge/frustration.json +19 -0
- package/src/rollup.ts +41 -20
- package/src/server.ts +67 -27
- package/src/shared-types.ts +7 -0
- package/src/trace.ts +54 -40
- package/src/types.ts +13 -1
- package/src/user-metrics.ts +220 -6
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { MessageKey } from "./en.js";
|
|
2
|
+
/**
|
|
3
|
+
* Simplified Chinese overrides. Incomplete on purpose in source: the coverage
|
|
4
|
+
* test (`packages/stats/test/i18n-coverage.test.ts`) fails on any missing key,
|
|
5
|
+
* which keeps a half-translated page out of a release without breaking builds
|
|
6
|
+
* mid-flight.
|
|
7
|
+
*/
|
|
8
|
+
export declare const zhCNMessages: Partial<Record<MessageKey, string>>;
|
|
9
|
+
/** The Simplified Chinese locale pack. */
|
|
10
|
+
export declare const zhCNLocale: {
|
|
11
|
+
readonly id: "zh-CN";
|
|
12
|
+
readonly messages: Partial<Record<"common.aborted" | "common.average" | "common.cache-read" | "common.cache-write" | "common.cancel" | "common.close" | "common.copied" | "common.copy" | "common.cost" | "common.duration" | "common.entry-id" | "common.error" | "common.error-rate" | "common.failed" | "common.filter" | "common.input" | "common.model" | "common.models" | "common.no-data-in-range" | "common.nothing-here-yet" | "common.other-n" | "common.output" | "common.output-message" | "common.output-tokens-per-second" | "common.pages" | "common.premium" | "common.premium-requests" | "common.project" | "common.provider" | "common.providers" | "common.range-1h" | "common.range-24h" | "common.range-30d" | "common.range-7d" | "common.range-90d" | "common.range-all" | "common.request" | "common.request-id" | "common.requests" | "common.root" | "common.session-entry" | "common.share" | "common.show-more" | "common.started" | "common.time-range" | "common.tokens" | "common.tokens-per-second" | "common.total" | "common.unknown" | "common.window-1h" | "common.window-24h" | "common.window-30d" | "common.window-7d" | "common.window-90d" | "common.window-all" | "costs.active-days-n" | "costs.active-days-one" | "costs.all-priced" | "costs.api-equivalent-estimate" | "costs.api-estimate-title" | "costs.average-per-day" | "costs.average-per-day-title" | "costs.by-component" | "costs.by-model" | "costs.by-model-description" | "costs.daily-by-component" | "costs.daily-by-model" | "costs.daily-estimate" | "costs.description" | "costs.empty-hint" | "costs.estimate" | "costs.estimate-by-component" | "costs.estimate-title" | "costs.no-priced-usage" | "costs.no-usage-in-range" | "costs.nothing-priced-yet" | "costs.per-priced-request" | "costs.per-priced-request-title" | "costs.per-request" | "costs.per-request-title" | "costs.priced-n" | "costs.requests-n" | "costs.split" | "costs.split-by" | "costs.split-title" | "costs.title" | "costs.top-model" | "costs.top-model-hint" | "costs.unpriced" | "costs.unpriced-column-title" | "costs.unpriced-hint" | "costs.unpriced-note-n" | "costs.unpriced-note-one" | "costs.unpriced-requests" | "costs.unpriced-title" | "costs.where-it-went" | "errors.affected-models" | "errors.by-model" | "errors.by-model-description" | "errors.cost-hint" | "errors.description" | "errors.empty-all-succeeded" | "errors.empty-no-affected-models" | "errors.empty-no-failures" | "errors.error-signatures" | "errors.failures" | "errors.filtered-of-total" | "errors.footer" | "errors.group-meta" | "errors.hint-in-window" | "errors.hint-latest-loaded" | "errors.last-failure" | "errors.last-seen" | "errors.load-latest" | "errors.loading" | "errors.loading-failures" | "errors.more-models" | "errors.no-match" | "errors.no-match-hint" | "errors.none-in-window" | "errors.open-latest" | "errors.search-placeholder" | "errors.signature" | "errors.signatures" | "errors.signatures-card-description" | "errors.signatures-hint" | "errors.signatures-top" | "errors.title" | "errors.unknown-error" | "errors.when" | "frustration.all-classes" | "frustration.all-judged" | "frustration.angry" | "frustration.angry-title" | "frustration.annoyed" | "frustration.annoyed-title" | "frustration.at-assistant" | "frustration.at-assistant-title" | "frustration.by-model" | "frustration.by-model-description" | "frustration.cancel-run" | "frustration.cancelled" | "frustration.cancelling" | "frustration.classify" | "frustration.column-judged" | "frustration.column-messages" | "frustration.column-model-ids" | "frustration.cost-so-far" | "frustration.coverage-hint" | "frustration.coverage-unscored" | "frustration.description" | "frustration.done" | "frustration.elapsed" | "frustration.estimate-note" | "frustration.estimated-cost" | "frustration.estimating" | "frustration.every-model-class" | "frustration.failed" | "frustration.failed-n" | "frustration.failed-suffix" | "frustration.hatch-title" | "frustration.hide-regex-title" | "frustration.in-flight" | "frustration.in-time" | "frustration.include-small" | "frustration.input-tokens" | "frustration.judge-coverage" | "frustration.judge-coverage-title" | "frustration.judge-description" | "frustration.judge-model" | "frustration.judge-panel" | "frustration.judge-running" | "frustration.judge-with" | "frustration.last-run-cancelled" | "frustration.last-run-done" | "frustration.last-run-failed" | "frustration.legend-angry" | "frustration.legend-annoyed-any" | "frustration.legend-assistant" | "frustration.legend-hatched" | "frustration.legend-hatched-run" | "frustration.legend-hue" | "frustration.legend-other" | "frustration.legend-trend" | "frustration.messages-n" | "frustration.messages-progress" | "frustration.model-class" | "frustration.model-versions" | "frustration.mostly-regex" | "frustration.no-messages" | "frustration.no-model-match" | "frustration.no-run-yet" | "frustration.not-run-yet" | "frustration.proceed" | "frustration.prose-chars" | "frustration.quote-title" | "frustration.regex-badge" | "frustration.regex-only" | "frustration.row-mostly-regex" | "frustration.run-cancelled-after" | "frustration.run-cancelled-line" | "frustration.run-done-line" | "frustration.run-failed-after" | "frustration.run-failed-line" | "frustration.run-judged" | "frustration.running" | "frustration.small-models-title" | "frustration.stack-relation" | "frustration.starting" | "frustration.table-description" | "frustration.title" | "frustration.try-longer-range" | "frustration.unclassified" | "frustration.unjudged-messages" | "frustration.unknown-error" | "frustration.unscored-line" | "frustration.user-messages" | "frustration.user-messages-title" | "gain.all-projects" | "gain.by-source" | "gain.by-source-description" | "gain.cumulative" | "gain.description" | "gain.description-scoped" | "gain.empty-hint-all" | "gain.empty-hint-longer-range" | "gain.empty-title" | "gain.empty-title-scoped" | "gain.hits" | "gain.reduction" | "gain.reduction-title" | "gain.reduction-unknown" | "gain.saved-bytes" | "gain.saved-per-day" | "gain.saved-per-hit" | "gain.saved-tokens" | "gain.savings-over-time" | "gain.savings-over-time-description" | "gain.source" | "gain.title" | "models.across-providers" | "models.across-providers-one" | "models.all-models" | "models.api-cost" | "models.api-cost-title" | "models.avg-duration" | "models.avg-ttft" | "models.bucket-5m" | "models.bucket-day" | "models.bucket-hour" | "models.cache-rate" | "models.cache-savings" | "models.cache-title" | "models.cost-title" | "models.count-desc" | "models.efficiency" | "models.empty-hint" | "models.empty-title" | "models.errors" | "models.failed-n" | "models.first-last-seen" | "models.latency" | "models.most-used" | "models.most-used-hint" | "models.no-samples-hint" | "models.no-samples-title" | "models.performance-per-bucket" | "models.request-share" | "models.share-desc" | "models.share-mode-aria" | "models.subtitle" | "models.table-desc" | "models.tok-per-second" | "models.tokens-title" | "models.tps-title" | "models.trend" | "models.trend-title" | "models.ttft" | "models.ttft-title" | "models.uncached-input" | "models.unpriced-n" | "models.used" | "nav.activity" | "nav.breadcrumb-stats" | "nav.costs" | "nav.dashboard" | "nav.errors" | "nav.frustration" | "nav.gain" | "nav.insights" | "nav.models" | "nav.open-navigation" | "nav.overview" | "nav.pages" | "nav.projects" | "nav.providers" | "nav.requests" | "nav.tools" | "nav.traces" | "nav.usage" | "overview.activity" | "overview.advisor" | "overview.all-requests" | "overview.api-cost-title" | "overview.api-equivalent" | "overview.api-equivalent-cost" | "overview.avg-latency" | "overview.avg-ttft" | "overview.by-agent" | "overview.cache-rate" | "overview.cache-rate-title" | "overview.cache-saved" | "overview.conversation-tokens" | "overview.description" | "overview.failed-n" | "overview.latest-requests" | "overview.latest-requests-description" | "overview.main-agent" | "overview.ok" | "overview.output-n" | "overview.per-5m" | "overview.per-day" | "overview.per-hour" | "overview.requests-short" | "overview.status" | "overview.subagents" | "overview.succeeded" | "overview.succeeded-n" | "overview.title" | "overview.token-mix" | "overview.token-mix-description" | "overview.tokens-title" | "overview.uncached-input" | "overview.unpriced-n" | "overview.when" | "projects.api-equivalent-cost" | "projects.api-equivalent-cost-hint" | "projects.api-equivalent-cost-rates" | "projects.avg-duration" | "projects.cache-rate" | "projects.cache-rate-hint" | "projects.cache-rate-hint-all" | "projects.cache-savings" | "projects.cache-savings-hint" | "projects.conversation-tokens" | "projects.conversation-tokens-hint" | "projects.description" | "projects.empty-no-folders" | "projects.empty-no-match" | "projects.empty-only-temporary" | "projects.errors" | "projects.failed-n" | "projects.filter-placeholder" | "projects.folder" | "projects.folders" | "projects.folders-n" | "projects.folders-of-n" | "projects.hide-temporary" | "projects.hide-temporary-hint" | "projects.hint-longer-range" | "projects.hint-temporary-hidden" | "projects.last-active" | "projects.share-of-cost" | "projects.share-of-requests" | "projects.temp" | "projects.temporary-n" | "projects.title" | "projects.top-by-cost" | "projects.top-by-cost-description" | "projects.top-by-requests" | "projects.top-by-requests-description" | "projects.unpriced-n" | "providers.account" | "providers.accounts" | "providers.accounts-needed" | "providers.accounts-needed-title" | "providers.accounts-title" | "providers.all-providers" | "providers.api-cost-title" | "providers.api-equivalent-cost" | "providers.bucket-5m" | "providers.bucket-day" | "providers.bucket-hour" | "providers.burn" | "providers.burn-description" | "providers.burn-estimate-description" | "providers.cost-title" | "providers.description" | "providers.exhausted" | "providers.exhausted-n" | "providers.exhaustions" | "providers.exhaustions-title" | "providers.failed-n" | "providers.high" | "providers.hours-description" | "providers.ideal-accounts" | "providers.latest-used" | "providers.models-title" | "providers.most-tokens" | "providers.no-activity-in-range" | "providers.no-provider-activity" | "providers.no-reading" | "providers.no-requests-in-range" | "providers.no-snapshots-in-range" | "providers.no-utilization-readings" | "providers.peak-burn-hours" | "providers.peak-hours-description" | "providers.peak-in-range" | "providers.peak-utilization" | "providers.peak-utilization-title" | "providers.premium-title" | "providers.recorded" | "providers.resets" | "providers.resets-title" | "providers.share-title" | "providers.snapshot-hint" | "providers.snapshots" | "providers.status" | "providers.subscription-windows" | "providers.subscription-windows-description" | "providers.succeeded-n" | "providers.tokens-peak-hour" | "providers.tokens-per-window" | "providers.tokens-per-window-title" | "providers.tokens-title" | "providers.too-little-consumed" | "providers.totals" | "providers.totals-description" | "providers.totals-description-unpriced-n" | "providers.totals-description-unpriced-one" | "providers.tps-title" | "providers.unpriced-n" | "providers.utilization" | "providers.utilization-description" | "providers.utilization-description-plain" | "providers.window" | "providers.windows-burned" | "providers.windows-burned-title" | "requests.api-equivalent-cost" | "requests.cache-read-title" | "requests.cache-write" | "requests.cost-estimate" | "requests.cost-hint" | "requests.description" | "requests.empty-in-window" | "requests.empty-no-match" | "requests.empty-no-match-hint" | "requests.failed-hint" | "requests.footer" | "requests.load-latest" | "requests.loading" | "requests.log-count-in-window" | "requests.log-count-latest" | "requests.log-loading" | "requests.log-title" | "requests.median-duration" | "requests.median-ttft" | "requests.none-in-window" | "requests.p95" | "requests.search-placeholder" | "requests.since" | "requests.status" | "requests.status-all" | "requests.tokens-hint" | "requests.ttft" | "requests.ttft-hint" | "requests.uncached-input" | "requests.unpriced-n" | "requests.when" | "shell.building-rollups" | "shell.dark-theme" | "shell.indexing" | "shell.ingesting" | "shell.jump-hint" | "shell.just-now" | "shell.light-theme" | "shell.live" | "shell.lost-connection" | "shell.range-suffix" | "shell.reconnecting" | "shell.sync-failed" | "shell.sync-now" | "shell.syncing" | "shell.system-theme" | "tools.all-tools" | "tools.api-equivalent" | "tools.args" | "tools.args-chars-title" | "tools.attr-cost" | "tools.attr-tokens" | "tools.attributed-cost" | "tools.attributed-tokens" | "tools.attribution-estimate" | "tools.attribution-note" | "tools.avg-args-per-call" | "tools.avg-result-per-call" | "tools.bucket-5m" | "tools.bucket-day" | "tools.bucket-hour" | "tools.by-tool" | "tools.by-tool-and-model" | "tools.by-tool-and-model-description" | "tools.by-tool-description" | "tools.call-arguments" | "tools.calls" | "tools.calls-over-time" | "tools.chars" | "tools.chart-description" | "tools.clear-tool-filter" | "tools.description" | "tools.distinct-tools" | "tools.error-rate-title" | "tools.errors" | "tools.errors-over-time" | "tools.errors-title" | "tools.failed-n" | "tools.filter-by-tool" | "tools.last-used" | "tools.most-used" | "tools.no-calls-to-tool" | "tools.no-tool-calls" | "tools.no-tool-errors" | "tools.result" | "tools.result-chars-title" | "tools.result-per-call" | "tools.result-per-call-title" | "tools.result-text" | "tools.share-of-calls" | "tools.share-of-cost" | "tools.share-of-tokens" | "tools.succeeded-n" | "tools.title" | "tools.tokens-output" | "tools.tool" | "tools.tool-calls" | "tools.trend" | "tools.trend-title" | "tools.unpriced-requests-n" | "trace.agent" | "trace.agents" | "trace.args" | "trace.avg" | "trace.axis-mode" | "trace.background" | "trace.bg" | "trace.calls" | "trace.canvas-aria" | "trace.collapse-all" | "trace.collapse-track" | "trace.compress-idle" | "trace.copy-json" | "trace.description" | "trace.empty-hint" | "trace.empty-title" | "trace.error-message" | "trace.errors" | "trace.expand-all" | "trace.expand-track" | "trace.failed-n" | "trace.filter-placeholder" | "trace.idle" | "trace.io-cached" | "trace.load-failed" | "trace.max" | "trace.minimap-aria" | "trace.mode-calls-title" | "trace.mode-time-title" | "trace.mode-turns-title" | "trace.model-time" | "trace.most-recent" | "trace.most-recent-filtered" | "trace.next-match" | "trace.no-matching-events" | "trace.no-matching-hint" | "trace.no-matching-title" | "trace.of-wall" | "trace.open-child-track" | "trace.previous-match" | "trace.raw-entry" | "trace.refresh" | "trace.search-placeholder" | "trace.session" | "trace.sessions" | "trace.start" | "trace.stop-reason" | "trace.task" | "trace.text" | "trace.thinking" | "trace.timeline" | "trace.timeline-hint" | "trace.title" | "trace.tok" | "trace.tool" | "trace.tool-aggregates" | "trace.tool-aggregates-desc" | "trace.tool-calls-n" | "trace.tool-time" | "trace.tools" | "trace.track" | "trace.transcript" | "trace.transcript-description" | "trace.ttft" | "trace.turns" | "trace.unterminated" | "trace.wall-time" | "ui.api" | "ui.delta-new" | "ui.json" | "ui.open-trace" | "ui.retry" | "ui.section-cost" | "ui.section-identity" | "ui.section-timing" | "ui.session-file" | "ui.show-fewer" | "ui.stats-row" | "ui.status-ok" | "ui.stop-reason" | "ui.table-shown-of" | "ui.time-to-first-token" | "ui.trace" | "ui.uncached-input", string>>;
|
|
13
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type { StatsLocale } from "../../locale.js";
|
|
2
|
+
import type { StatsLocale } from "../../locale.js";
|
|
3
|
+
/** Values a message may interpolate through `{name}` placeholders. */
|
|
4
|
+
export type TranslationParams = Record<string, string | number>;
|
|
5
|
+
/** A locale pack: the messages one locale overrides, keyed by slug. */
|
|
6
|
+
export interface LocalePack {
|
|
7
|
+
readonly id: StatsLocale;
|
|
8
|
+
readonly messages: Readonly<Record<string, string>>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Messages for every locale, keyed first by locale id. `undefined` is part of
|
|
12
|
+
* the value type because a locale may override only some keys (English is the
|
|
13
|
+
* fallback for the rest).
|
|
14
|
+
*/
|
|
15
|
+
export type MessagesByLocale = Readonly<Record<StatsLocale, Readonly<Record<string, string | undefined>>>>;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Timeline overview strip: per-category density over the full virtual domain
|
|
3
3
|
* plus a draggable/resizable viewport brush, mirroring DevTools' overview.
|
|
4
|
+
* The density layer is painted once per trace/scale/size/theme into an
|
|
5
|
+
* offscreen canvas; pan and zoom only blit it and redraw the brush.
|
|
4
6
|
*/
|
|
5
7
|
import type { TraceTrack } from "../types.js";
|
|
6
8
|
import type { TimelineViewport } from "./TimelineCanvas.js";
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The trace flamegraph:
|
|
3
|
-
* labels, collapse chevrons) and a
|
|
4
|
-
*
|
|
5
|
-
* fit/focus keys, hover tooltips,
|
|
2
|
+
* The trace flamegraph: a DPR-scaled scene canvas with DOM hover/selection
|
|
3
|
+
* boxes on top, a DOM gutter (track/lane labels, collapse chevrons) and a
|
|
4
|
+
* DOM tooltip. Implements the Chrome DevTools interaction contract:
|
|
5
|
+
* cursor-anchored wheel zoom, drag pan, WASD, fit/focus keys, hover tooltips,
|
|
6
|
+
* click-to-select, double-click-to-zoom.
|
|
6
7
|
*/
|
|
7
|
-
import type { TraceTrack } from "../types.js";
|
|
8
|
+
import type { TraceSpan, TraceTrack } from "../types.js";
|
|
8
9
|
import { type TraceScale } from "./time-scale.js";
|
|
9
10
|
export interface TimelineViewport {
|
|
10
11
|
u0: number;
|
|
@@ -15,11 +16,31 @@ export interface TimelineCanvasProps {
|
|
|
15
16
|
scale: TraceScale;
|
|
16
17
|
viewport: TimelineViewport;
|
|
17
18
|
onViewportChange: (viewport: TimelineViewport) => void;
|
|
18
|
-
|
|
19
|
+
/** The selected span with its track (resolved by the trace view). */
|
|
20
|
+
selected: {
|
|
21
|
+
span: TraceSpan;
|
|
22
|
+
track: TraceTrack;
|
|
23
|
+
} | null;
|
|
19
24
|
onSelect: (spanId: string | null) => void;
|
|
20
|
-
search
|
|
25
|
+
/** Spans matching the search; `null` when not searching (everything at full opacity). */
|
|
26
|
+
matchIds: ReadonlySet<string> | null;
|
|
21
27
|
collapsed: ReadonlySet<string>;
|
|
22
28
|
onToggleCollapse: (trackId: string) => void;
|
|
23
29
|
traceStart: number;
|
|
24
30
|
}
|
|
25
|
-
|
|
31
|
+
/** Per-lane span positions on the virtual axis, parallel to `LaneRow.spans`. */
|
|
32
|
+
interface LaneAxis {
|
|
33
|
+
startU: Float64Array;
|
|
34
|
+
endU: Float64Array;
|
|
35
|
+
/** Running max of `endU`; monotonic, so the first visible span is a binary search away. */
|
|
36
|
+
maxEndU: Float64Array;
|
|
37
|
+
}
|
|
38
|
+
export declare function buildLaneAxes(layout: {
|
|
39
|
+
lanes: ReadonlyArray<{
|
|
40
|
+
spans: ReadonlyArray<Pick<TraceSpan, "start" | "end">>;
|
|
41
|
+
}>;
|
|
42
|
+
}, scale: Pick<TraceScale, "toU">): LaneAxis[];
|
|
43
|
+
/** First index whose running-max end reaches `u0`: every earlier span ends before the viewport. */
|
|
44
|
+
export declare function firstVisible(maxEndU: Float64Array, u0: number): number;
|
|
45
|
+
export declare function TimelineCanvas({ tracks, scale, viewport, onViewportChange, selected, onSelect, matchIds, collapsed, onToggleCollapse, traceStart, }: TimelineCanvasProps): import("react").JSX.Element;
|
|
46
|
+
export {};
|
|
@@ -17,8 +17,10 @@ export interface TranscriptListProps {
|
|
|
17
17
|
selection: string | null;
|
|
18
18
|
onSelect: (spanId: string) => void;
|
|
19
19
|
search: string;
|
|
20
|
+
/** Spans matching `search` (from the trace view); `null` when not searching. */
|
|
21
|
+
matchIds: ReadonlySet<string> | null;
|
|
20
22
|
traceStart: number;
|
|
21
23
|
}
|
|
22
24
|
/** Flatten all spans and markers across tracks into chronological rows. */
|
|
23
25
|
export declare function buildTranscriptRows(tracks: TraceTrack[]): TranscriptRow[];
|
|
24
|
-
export declare
|
|
26
|
+
export declare const TranscriptList: import("react").MemoExoticComponent<({ tracks, selection, onSelect, search, matchIds, traceStart, }: TranscriptListProps) => import("react").JSX.Element>;
|
package/dist/types/db.d.ts
CHANGED
|
@@ -49,12 +49,23 @@ export interface ParsedSession {
|
|
|
49
49
|
/** Recover missing rows from a full-history scan without rewriting unchanged records. */
|
|
50
50
|
replay: boolean;
|
|
51
51
|
}
|
|
52
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* Commit distinct transcripts' rows, reconciliation state, and cursors together; failure rolls back the batch.
|
|
54
|
+
* `changes` counts stored rows inserted, updated or deleted (cursor bookkeeping excluded), so callers can
|
|
55
|
+
* tell a batch that changed nothing.
|
|
56
|
+
*/
|
|
53
57
|
export declare function applySessionParseResults(sessions: ParsedSession[]): {
|
|
54
58
|
processed: number;
|
|
55
59
|
files: number;
|
|
56
60
|
reconcile: boolean;
|
|
61
|
+
changes: number;
|
|
57
62
|
};
|
|
63
|
+
/**
|
|
64
|
+
* SQLite `PRAGMA data_version` of the open connection, or null before
|
|
65
|
+
* {@link initDb}. It moves only when another connection (another omp process)
|
|
66
|
+
* commits, so a caller can detect foreign writes without scanning.
|
|
67
|
+
*/
|
|
68
|
+
export declare function getDataVersion(): number | null;
|
|
58
69
|
export declare function prepareSessionSync(): boolean;
|
|
59
70
|
export declare function completeSessionSync(reconcile: boolean): void;
|
|
60
71
|
/**
|
|
@@ -90,32 +101,14 @@ export declare function getMessageById(id: number): MessageStats | null;
|
|
|
90
101
|
* Self-initializing (opens the stats DB on first use) so the coding-agent TUI
|
|
91
102
|
* can query without the dashboard server's init flow. Days use the machine's
|
|
92
103
|
* timezone — this is a localhost tool, same rationale as
|
|
93
|
-
* {@link getProviderHourlyBurn}.
|
|
104
|
+
* {@link getProviderHourlyBurn}. Reads the hourly rollup, falling back to the
|
|
105
|
+
* raw rows while its rebuild backlog is too large for exact reads.
|
|
94
106
|
*/
|
|
95
107
|
export declare function getDailyActivity(days?: number): Promise<DailyActivityPoint[]>;
|
|
96
108
|
/**
|
|
97
109
|
* Settle every full-session backfill after a successful sync pass.
|
|
98
110
|
*/
|
|
99
111
|
export declare function markSessionBackfillsComplete(): void;
|
|
100
|
-
export interface PruneOrphanResult {
|
|
101
|
-
/** Distinct session files whose rows were removed. */
|
|
102
|
-
prunedFiles: number;
|
|
103
|
-
/** Total rows removed across all session-keyed tables. */
|
|
104
|
-
deletedRows: number;
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Delete every row whose `session_file` no longer exists on disk. Deleted
|
|
108
|
-
* projects (tmp test suites, wiped transcripts) otherwise keep surfacing in
|
|
109
|
-
* the Operational Feed and models list forever. Runs in one transaction; the
|
|
110
|
-
* existing-file set is collected by the caller before any DELETE so the
|
|
111
|
-
* comparison is a single in-memory set probe per stored path.
|
|
112
|
-
*/
|
|
113
|
-
export declare function pruneOrphanSessionsInDb(database: Database, existingFiles: readonly string[]): PruneOrphanResult;
|
|
114
|
-
/**
|
|
115
|
-
* {@link pruneOrphanSessionsInDb} against the module DB handle. No-op when
|
|
116
|
-
* {@link initDb} has not run.
|
|
117
|
-
*/
|
|
118
|
-
export declare function pruneOrphanSessions(existingFiles: readonly string[]): PruneOrphanResult;
|
|
119
112
|
/**
|
|
120
113
|
* Insert user-message stats. Idempotent via UNIQUE(session_file, entry_id).
|
|
121
114
|
* The `WHERE NOT EXISTS` clause matches {@link insertMessageStats}: forks
|
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
* prepacked npm bundle, and reset to an empty file afterwards so the dev tree
|
|
8
8
|
* keeps building the dashboard from source.
|
|
9
9
|
*/
|
|
10
|
+
/**
|
|
11
|
+
* Cheap check whether the generated text carries a gzip archive: sniffs the
|
|
12
|
+
* base64 of the gzip magic (`1f 8b 08`) without decoding megabytes.
|
|
13
|
+
*/
|
|
14
|
+
export declare function hasEmbeddedClientArchive(txt: string): boolean;
|
|
10
15
|
/**
|
|
11
16
|
* Decode the generated archive text.
|
|
12
17
|
*
|
|
@@ -16,26 +16,35 @@
|
|
|
16
16
|
* using the judge the omp host registered through `startServer`. Standalone
|
|
17
17
|
* `omp-stats` has none and only shows the regex fallback.
|
|
18
18
|
*/
|
|
19
|
-
import
|
|
19
|
+
import { type Judge, type Model } from "@linxiraos/pi-ai";
|
|
20
20
|
import { type FrustrationModelRow } from "./db.js";
|
|
21
21
|
import type { FrustrationDashboardStats, FrustrationEstimate, FrustrationJobStatus, FrustrationModelStats } from "./shared-types.js";
|
|
22
22
|
/** Judge supplied by the omp host process; `primaryModel` prices the pre-run estimate. */
|
|
23
23
|
export interface StatsJudge extends Judge {
|
|
24
24
|
primaryModel(): Model | undefined;
|
|
25
25
|
}
|
|
26
|
-
/** Lazily resolves the host judge on first estimate/run so `
|
|
26
|
+
/** Lazily resolves the host judge on first estimate/run so `zetacode stats` startup stays fast. */
|
|
27
27
|
export type StatsJudgeProvider = () => Promise<StatsJudge>;
|
|
28
|
-
/** Where the user's annoyance is aimed. */
|
|
29
|
-
export type FrustrationTarget = "assistant" | "other" | "none";
|
|
30
28
|
/**
|
|
31
|
-
* The two questions asked about every prose text, in ONE judge request
|
|
29
|
+
* The two questions asked about every prose text, in ONE judge request:
|
|
30
|
+
* `annoyed` (four levels) and `target` (`assistant`, `other`, or `none`).
|
|
32
31
|
* The cost constants below were measured with exactly these strings; changing
|
|
33
32
|
* them invalidates both the estimate and every cached verdict's meaning.
|
|
34
33
|
*/
|
|
35
|
-
export declare const FRUSTRATION_QUESTIONS: {
|
|
36
|
-
annoyed:
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
export declare const FRUSTRATION_QUESTIONS: import("@linxiraos/pi-ai").QuestionsFor<{
|
|
35
|
+
annoyed: {
|
|
36
|
+
instructions: string;
|
|
37
|
+
criteria: string[];
|
|
38
|
+
};
|
|
39
|
+
target: {
|
|
40
|
+
instructions: string;
|
|
41
|
+
criteria: {
|
|
42
|
+
assistant: string;
|
|
43
|
+
other: string;
|
|
44
|
+
none: string;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
}>;
|
|
39
48
|
/** Register (or replace) the host judge. Called by `startServer`. */
|
|
40
49
|
export declare function setStatsJudgeProvider(provider: StatsJudgeProvider | undefined): void;
|
|
41
50
|
/** Snapshot of the current run's progress. */
|
package/dist/types/live.d.ts
CHANGED
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
* The dashboard never waits for ingest. {@link StatsLive.start} kicks a full
|
|
6
6
|
* sync in the background and watches the sessions directory; changed
|
|
7
7
|
* transcripts are re-synced (only those files) shortly after they are written.
|
|
8
|
-
* Every
|
|
9
|
-
* pages refetch and fill in while parsing is still
|
|
8
|
+
* Every batch that changes stored rows bumps {@link LiveStatus.version}
|
|
9
|
+
* (throttled), so open pages refetch and fill in while parsing is still
|
|
10
|
+
* running; syncs that change nothing leave the version alone.
|
|
10
11
|
*/
|
|
11
12
|
import type { LiveStatus } from "./shared-types.js";
|
|
12
|
-
|
|
13
|
+
/** Receives each distinct status and its JSON serialization (shared by every listener). */
|
|
14
|
+
type Listener = (status: LiveStatus, frame: string) => void;
|
|
13
15
|
/** One per process; owned by the dashboard server (see `startServer`). */
|
|
14
16
|
export declare class StatsLive {
|
|
15
17
|
#private;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locale resolution shared by the stats server (which stamps the host's
|
|
3
|
+
* language into the served HTML) and the client bundle (which renders it).
|
|
4
|
+
* Lives outside `client/` so the server never imports browser code.
|
|
5
|
+
*/
|
|
6
|
+
/** Locales the dashboard ships: English and Simplified Chinese. */
|
|
7
|
+
export type StatsLocale = "en" | "zh-CN";
|
|
8
|
+
/**
|
|
9
|
+
* Map a language tag to a shipped locale. Any `zh` variant is Simplified
|
|
10
|
+
* Chinese (the dashboard ships no Traditional pack); everything else —
|
|
11
|
+
* including browser tags such as `tr-TR` — is English, matching the
|
|
12
|
+
* dashboard's single number/date convention rather than the browser's.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveLocaleTag(tag: string | undefined | null): StatsLocale;
|
|
15
|
+
/** Pick the first shipped locale from a `navigator.languages` list; English when none match. */
|
|
16
|
+
export declare function resolveBrowserLocale(languages: readonly string[] | undefined): StatsLocale;
|
package/dist/types/parser.d.ts
CHANGED
|
@@ -18,23 +18,6 @@ export declare function classifyAgentType(sessionPath: string): AgentType;
|
|
|
18
18
|
* The folder part uses -- as path separator.
|
|
19
19
|
*/
|
|
20
20
|
export declare function extractFolderFromPath(sessionPath: string): string;
|
|
21
|
-
/**
|
|
22
|
-
* Decode a session project folder name back to its source cwd, mirroring the
|
|
23
|
-
* encoder in the coding agent's session-paths module: home-relative cwds
|
|
24
|
-
* encode as `-<segments>`, temp-relative ones as `-tmp<segments>`, and legacy
|
|
25
|
-
* absolute ones as `--<absolute>--`, with `/`, `\`, and `:` collapsed to `-`.
|
|
26
|
-
* Returns null when the name carries no decodable cwd.
|
|
27
|
-
*/
|
|
28
|
-
export declare function decodeProjectFolderCwd(projectDir: string): string | null;
|
|
29
|
-
/**
|
|
30
|
-
* Whether a session project folder decodes to a cwd inside the OS temp dir.
|
|
31
|
-
* Test suites spawn agents under `os.tmpdir()` and re-create their transcripts
|
|
32
|
-
* on every run; those sessions are throwaway usage that must not reach the
|
|
33
|
-
* stats DB. The `-` collapse in the encoder is lossy (a literal `-` inside a
|
|
34
|
-
* path segment is indistinguishable from a separator), which can only produce
|
|
35
|
-
* false positives here — a skipped ingestion, never a misattributed row.
|
|
36
|
-
*/
|
|
37
|
-
export declare function isTempProjectFolder(projectDir: string): boolean;
|
|
38
21
|
/**
|
|
39
22
|
* Token-bucket view for total derivation. Persisted session payloads are
|
|
40
23
|
* outside-controlled (old versions, foreign producers), so every counter is
|
package/dist/types/rollup.d.ts
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* (an hour of data is small and indexed by timestamp).
|
|
26
26
|
*/
|
|
27
27
|
import type { Database } from "bun:sqlite";
|
|
28
|
-
import type { AgentTypeStats, AggregatedStats, CostTimeSeriesPoint, FolderStats, ModelPerformancePoint, ModelStats, ModelTimeSeriesPoint, ProviderAggregate, ProviderHourlyPoint, ProviderTimeSeriesPoint, TimeSeriesPoint, ToolModelStats, ToolTimeSeriesPoint, ToolUsageStats } from "./types.js";
|
|
28
|
+
import type { AgentTypeStats, AggregatedStats, CostTimeSeriesPoint, DailyActivityPoint, FolderStats, ModelPerformancePoint, ModelStats, ModelTimeSeriesPoint, ProviderAggregate, ProviderHourlyPoint, ProviderTimeSeriesPoint, TimeSeriesPoint, ToolModelStats, ToolTimeSeriesPoint, ToolUsageStats } from "./types.js";
|
|
29
29
|
/**
|
|
30
30
|
* Create (or rebuild after a version bump) the rollup tables and the triggers
|
|
31
31
|
* that mark hours dirty. Called from `initDb` after the raw tables exist.
|
|
@@ -87,6 +87,14 @@ export declare function getStatsByProvider(cutoff?: number | null): ProviderAggr
|
|
|
87
87
|
* up to 30 minutes.
|
|
88
88
|
*/
|
|
89
89
|
export declare function getProviderHourlyBurn(cutoff?: number | null): ProviderHourlyPoint[];
|
|
90
|
+
/**
|
|
91
|
+
* Per-local-day request/token/cost totals since `cutoff`, oldest first, read
|
|
92
|
+
* from the hourly rollup. Returns null when the local UTC offset is not a whole
|
|
93
|
+
* hour (now or at `cutoff`), since hourly buckets then straddle local midnight,
|
|
94
|
+
* or while the dirty backlog is too large for exact reads; callers then
|
|
95
|
+
* aggregate the raw rows instead.
|
|
96
|
+
*/
|
|
97
|
+
export declare function getDailyActivityFromRollup(cutoff: number): DailyActivityPoint[] | null;
|
|
90
98
|
/** Tokens/cost per bucket per provider. */
|
|
91
99
|
export declare function getProviderTimeSeries({ cutoff, bucketMs }: RangeWindow): ProviderTimeSeriesPoint[];
|
|
92
100
|
/** Per-transcript-file rollup for the Traces session list. */
|
package/dist/types/server.d.ts
CHANGED
|
@@ -16,5 +16,11 @@ export interface StatsServerHandle {
|
|
|
16
16
|
export interface StartServerOptions {
|
|
17
17
|
/** Host judge for the Frustration dashboard's judge runs; replaces any previously registered one. */
|
|
18
18
|
judge?: StatsJudgeProvider;
|
|
19
|
+
/**
|
|
20
|
+
* Host UI language (`zh`, `zh-CN`, `en`, …). Stamped into the served page so
|
|
21
|
+
* the dashboard renders in the same language as the CLI that launched it;
|
|
22
|
+
* anything unrecognized resolves to English.
|
|
23
|
+
*/
|
|
24
|
+
language?: string;
|
|
19
25
|
}
|
|
20
26
|
export declare function startServer(port?: number, hostname?: string, options?: StartServerOptions): Promise<StatsServerHandle>;
|
|
@@ -191,6 +191,13 @@ export interface FrustrationCounts {
|
|
|
191
191
|
messages: number;
|
|
192
192
|
/** Messages whose prose has a cached judge verdict; the rest use regex fallback. */
|
|
193
193
|
judged: number;
|
|
194
|
+
/**
|
|
195
|
+
* Unjudged messages whose prose is written in a script no lexicon covers
|
|
196
|
+
* (Kana, Hangul, Cyrillic, …). Their regex counts are zeros because there is
|
|
197
|
+
* no lexicon, not because the user was calm - the dashboard says so instead
|
|
198
|
+
* of folding them into "not annoyed", and the judge is the fix for them.
|
|
199
|
+
*/
|
|
200
|
+
unscored: number;
|
|
194
201
|
/** Annoyed at anything (the assistant, tooling, other people, ...). */
|
|
195
202
|
annoyed: number;
|
|
196
203
|
/** Annoyed and aimed at the assistant. Subset of `annoyed`. */
|
package/dist/types/trace.d.ts
CHANGED
|
@@ -18,18 +18,30 @@ export declare class TracePathError extends Error {
|
|
|
18
18
|
* against an unchanged transcript mtime.
|
|
19
19
|
*/
|
|
20
20
|
export declare const TRACE_ETAG_VERSION = 3;
|
|
21
|
+
/** Freshness of a root trace: root mtime plus the child-transcript set fingerprint. */
|
|
22
|
+
export interface TraceFingerprint {
|
|
23
|
+
rootMtimeMs: number;
|
|
24
|
+
childFingerprint: string;
|
|
25
|
+
}
|
|
21
26
|
/**
|
|
22
|
-
* Freshness fingerprint for the trace ETag pre-check
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
27
|
+
* Freshness fingerprint for the trace ETag pre-check; `SessionTrace.etag` is
|
|
28
|
+
* `${rootMtimeMs}:${childFingerprint}` for an unraced build. Returns undefined
|
|
29
|
+
* when the path is rejected or missing (the caller falls through to the full
|
|
30
|
+
* build, which maps those to 400/404).
|
|
26
31
|
*/
|
|
27
|
-
export declare function traceFingerprintForEtag(fileParam: string): Promise<
|
|
32
|
+
export declare function traceFingerprintForEtag(fileParam: string): Promise<TraceFingerprint | undefined>;
|
|
28
33
|
export declare function traceMemoForTests(): {
|
|
29
34
|
file: string;
|
|
30
35
|
mtimeMs: number;
|
|
31
36
|
} | undefined;
|
|
32
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Assemble the full span tree for one root session transcript.
|
|
39
|
+
* Throws {@link TracePathError} for paths outside the sessions root; ENOENT
|
|
40
|
+
* passes through for the caller's 404 mapping. `fingerprint` may carry the
|
|
41
|
+
* {@link traceFingerprintForEtag} value the caller just computed for the same
|
|
42
|
+
* file (its ETag pre-check), sparing a second walk.
|
|
43
|
+
*/
|
|
44
|
+
export declare function buildSessionTrace(fileParam: string, fingerprint?: TraceFingerprint): Promise<SessionTrace>;
|
|
33
45
|
/** Fetch one full journal entry by id from a transcript, for the span drawer. */
|
|
34
46
|
export declare function getTraceEntry(fileParam: string, entryId: string): Promise<SessionEntry | null>;
|
|
35
47
|
/**
|
package/dist/types/types.d.ts
CHANGED
|
@@ -33,6 +33,14 @@ export interface MessageStats {
|
|
|
33
33
|
usage: Usage;
|
|
34
34
|
/** Which agent produced this message (main agent, task subagent, advisor) */
|
|
35
35
|
agentType: AgentType;
|
|
36
|
+
/**
|
|
37
|
+
* Service tier the provider reported serving this turn, or `null` when the
|
|
38
|
+
* provider reported none. Lets consumers separate a fast serving path's
|
|
39
|
+
* throughput and premium traffic from standard-tier traffic. Always written by
|
|
40
|
+
* `rowToMessageStats`; optional only because session fixtures that stand in
|
|
41
|
+
* for ingest input are typed as `MessageStats` too.
|
|
42
|
+
*/
|
|
43
|
+
serviceTier?: ServiceTier | null;
|
|
36
44
|
/**
|
|
37
45
|
* Ingest refused to price this request: a scheduled (time-based) card with no
|
|
38
46
|
* recoverable request timestamp, so `usage.cost.total` of 0 is unknown spend
|
|
@@ -61,7 +69,7 @@ export interface MessageStatsInput extends Omit<MessageStats, "usage" | "costUnp
|
|
|
61
69
|
export interface RequestDetails extends MessageStats {
|
|
62
70
|
/** The full conversation history or just the last turn. */
|
|
63
71
|
messages: unknown[];
|
|
64
|
-
/** The model's response. */
|
|
72
|
+
/** The model's response; `null` for `model_usage` entries, which journal no payload. */
|
|
65
73
|
output: unknown;
|
|
66
74
|
}
|
|
67
75
|
/**
|
|
@@ -162,6 +170,10 @@ export interface UserMessageStats {
|
|
|
162
170
|
repetition: number;
|
|
163
171
|
/** Second-person reproach ("you didnt", "why did you", "stop X-ing") */
|
|
164
172
|
blame: number;
|
|
173
|
+
/** Emphatic CJK/voice markers the caps-based yelling cannot see (see `UserMessageMetrics.emphasis`). */
|
|
174
|
+
emphasis: number;
|
|
175
|
+
/** 1 when the prose leans on a script no lexicon covers; such rows are unscored, not calm. */
|
|
176
|
+
unsupportedScript: number;
|
|
165
177
|
/** Judge-facing prose (see `judgeProse`); empty when the message was all markup. */
|
|
166
178
|
prose: string;
|
|
167
179
|
/** Hex `Bun.hash` of `prose`, keying the shared verdict cache; empty when `prose` is. */
|
|
@@ -60,6 +60,10 @@ export interface UserMessageMetrics {
|
|
|
60
60
|
*
|
|
61
61
|
* Bare `still` / `again` are too ambiguous to count alone (they show up
|
|
62
62
|
* in normal speech like "try again" or "still works").
|
|
63
|
+
*
|
|
64
|
+
* Also counts the Chinese recall/still markers (`我说过`, `还是不行`, `又错了`)
|
|
65
|
+
* and whole-message repetition of the previous user message (`prevText`),
|
|
66
|
+
* which is the signal that survives both languages and voice input.
|
|
63
67
|
*/
|
|
64
68
|
repetition: number;
|
|
65
69
|
/**
|
|
@@ -68,8 +72,24 @@ export interface UserMessageMetrics {
|
|
|
68
72
|
* - `you (didn't|did not|broke|missed|forgot|keep|always|never|still|ignored)`
|
|
69
73
|
* - `why (would|did) (you|u)`
|
|
70
74
|
* - sentence-leading `stop <verb>ing` imperatives
|
|
75
|
+
* - the Chinese forms (`你怎么又`, `你没改`, `我明明说过`, `不是让你`)
|
|
71
76
|
*/
|
|
72
77
|
blame: number;
|
|
78
|
+
/**
|
|
79
|
+
* Emphatic markers the caps-based {@link yelling} cannot see, because they
|
|
80
|
+
* are how Chinese - and any voice-transcribed text - shouts: full-width
|
|
81
|
+
* `!?` bursts, a Han character or short word repeated three or more times
|
|
82
|
+
* (`不不不`, `不对不对不对`), and elongated interjections (`啊啊啊`).
|
|
83
|
+
* English text scores 0 here; its shouting is already in {@link yelling}.
|
|
84
|
+
*/
|
|
85
|
+
emphasis: number;
|
|
86
|
+
/**
|
|
87
|
+
* 1 when the prose is dominated by a script no shipped lexicon covers
|
|
88
|
+
* (Kana, Hangul, Cyrillic, Arabic, …). The other counts are then *not*
|
|
89
|
+
* evidence of calm - they are evidence of a missing lexicon, and the
|
|
90
|
+
* dashboard reports those messages as unscored rather than as content.
|
|
91
|
+
*/
|
|
92
|
+
unsupportedScript: number;
|
|
73
93
|
}
|
|
74
94
|
/** Cap on the judge-facing prose stored per user message; longer prose is truncated. */
|
|
75
95
|
export declare const PROSE_MAX_CHARS = 4000;
|
|
@@ -84,6 +104,8 @@ export declare function judgeProse(text: string): string;
|
|
|
84
104
|
*
|
|
85
105
|
* `text` may be empty or whitespace; in that case every metric is 0.
|
|
86
106
|
*/
|
|
87
|
-
export declare function computeUserMessageMetrics(text: string
|
|
107
|
+
export declare function computeUserMessageMetrics(text: string, options?: {
|
|
108
|
+
/** The user message before this one in the same session, for whole-message repetition. */ prevText?: string;
|
|
109
|
+
}): UserMessageMetrics;
|
|
88
110
|
/** Empty metrics constant for callers that need a default. */
|
|
89
111
|
export declare const EMPTY_USER_METRICS: UserMessageMetrics;
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@linxiraos/pi-stats",
|
|
4
|
-
"version": "1.
|
|
5
|
-
"description": "Local observability dashboard for
|
|
4
|
+
"version": "1.2.0",
|
|
5
|
+
"description": "Local observability dashboard for omp AI usage statistics",
|
|
6
6
|
"homepage": "https://linxira-os.github.io/zeta/",
|
|
7
7
|
"author": "Linxira-OS",
|
|
8
8
|
"license": "MIT",
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
"fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@linxiraos/pi-ai": "1.
|
|
43
|
-
"@linxiraos/pi-catalog": "1.
|
|
44
|
-
"@linxiraos/pi-utils": "1.
|
|
42
|
+
"@linxiraos/pi-ai": "1.2.0",
|
|
43
|
+
"@linxiraos/pi-catalog": "1.2.0",
|
|
44
|
+
"@linxiraos/pi-utils": "1.2.0",
|
|
45
45
|
"lucide-react": "^1.24.0",
|
|
46
46
|
"react": "19.2.7",
|
|
47
47
|
"react-dom": "19.2.7"
|