opencode-usage-insights 0.1.0 → 0.1.1

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/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![Lint](https://img.shields.io/github/actions/workflow/status/hugobatista/opencode-usage-insights/lint.yml?label=Lint)](https://github.com/hugobatista/opencode-usage-insights/actions/workflows/lint.yml)
6
6
  [![npm](https://img.shields.io/npm/v/opencode-usage-insights.svg)](https://www.npmjs.com/package/opencode-usage-insights)
7
7
 
8
- OpenCode plugin for one question the host cannot answer: **which endpoint is
8
+ OpenCode plugin for one question the host cannot answer: **which provider is
9
9
  actually serving each model** — and what that costs. It shows a telemetry line
10
10
  above the composer after every finished turn and records every assistant step
11
11
  in a local SQLite file, read back through an interactive `/usage` panel.
@@ -18,23 +18,24 @@ written by the server-side recorder and read by the TUI.
18
18
  ## What it does
19
19
 
20
20
  - **The line** (`session.composer.top`): end time, the gap since the previous
21
- prompt, the endpoint that served the turn, turn and session token totals, and
22
- warnings when the prompt cache or the endpoint identity changed. It belongs to
23
- finished work, so it stays hidden while a turn is running.
24
- - **The `/usage` panel**: ten keyboard-driven views — `overview`, `models`,
25
- `endpoints`, `affinity`, `cache`, `periods`, `latency`, `sessions`, `turns`,
21
+ prompt, the provider and model that ran the turn, turn and session token
22
+ totals, and warnings when the prompt cache or the provider identity changed.
23
+ It belongs to finished work, so it stays hidden while a turn is running.
24
+ - **The `/usage` panel**: nine keyboard-driven views — `overview`, `models`,
25
+ `providers`, `cache`, `periods`, `latency`, `sessions`, `turns`,
26
26
  `db` — over five ranges (`session`, `today`, `7d`, `30d`, `all`), with
27
27
  drill-downs, sorting, filters and state remembered between openings.
28
- `/usage models 7d`, `/usage affinity`, `/usage endpoints 30d`.
28
+ `/usage models 7d`, `/usage providers 30d`, `/usage turns 7d`.
29
29
  - **The session sidebar**: the session's own totals and its last turns, in the
30
- same buckets as the line. Three lines per turn — when and through what, the
31
- prompt volumes, then `hit · tok/s · cost` — and the session's average
32
- throughput on its totals:
33
- `16:54 orcarouter-dsv4.1flash` / `in 1.7k (427.3k) · out 1.06k` /
34
- `hit 99.7% · 1.2k/s · $0.0006`.
30
+ same buckets as the line. Three lines per turn — when and through which
31
+ provider, the prompt volumes, then `hit · tok/s · cost` — plus the model at
32
+ both ends of the block and on any turn that changed it, so the history reads
33
+ whether it is the whole session or a window of a long one:
34
+ `16:54 opencode-go` / `deepseek-v4.1-flash max` /
35
+ `in 1.7k (427.3k) · out 1.06k` / `hit 99.7% · 1.2k/s · $0.0006`.
35
36
  - **The record** (server entry): every assistant step with tokens, cost,
36
- timings, finish reason, provider/model, session and parent ids, and the
37
- endpoint that served it; prompts, session lifecycle and compaction events too.
37
+ timings, finish reason, the provider and model it ran as, and its session and
38
+ parent ids; prompts, session lifecycle and compaction events too.
38
39
  - **Portable data** (from a checkout): `bun run report --ndjson` exports the
39
40
  whole database, and `--import` merges it back on another machine.
40
41
  - **Observational by design**: the plugin never rewrites prompts, requests or
@@ -49,7 +50,7 @@ written by the server-side recorder and read by the TUI.
49
50
 
50
51
  | | |
51
52
  | --- | --- |
52
- | **OS** | Linux, macOS and Windows. The database lives in the per-user state directory of each (table below). CI runs the data layer — paths, database, recorder, queries, panel assembly, dump round-trip, file permissions — on all three, and the whole suite (including the TUI render tests) on Linux. `bun run check:platform` runs that same check by hand. |
53
+ | **OS** | Linux, macOS and Windows. The database lives in the per-user state directory of each (table below); `test/paths.test.ts` asserts the path rules of all three from any machine, and `bun run check:platform` exercises the data layer — paths, database, recorder, queries, panel assembly, dump round-trip, file permissions — on the OS it runs on. CI runs the whole suite (including the TUI render tests) on Linux. |
53
54
  | **Runtime** | Bun, the runtime OpenCode ships with. SQLite comes from `bun:sqlite`: there is no native module to build and nothing to compile on install. |
54
55
 
55
56
  ## Install
@@ -87,7 +88,7 @@ To pass [options](#configuration), use the object form:
87
88
  ```jsonc
88
89
  {
89
90
  "plugins": [
90
- { "package": "opencode-usage-insights", "options": { "identity": "endpoint" } }
91
+ { "package": "opencode-usage-insights", "options": { "sidebarTurns": 5 } }
91
92
  ]
92
93
  }
93
94
  ```
@@ -115,16 +116,17 @@ turn finishes, and `/usage` (alias `/insights`) opens the panel.
115
116
  ## The line
116
117
 
117
118
  ```text
118
- 14:32:07 · Δ 3m12s · orcarouter-dsv4.1-flash-free · in 85.4k (1.62M), cached 1.53M, out 3.7k · sess in 2.1M (14.5M), cached 12.4M, out 88k · ⚠ cache expired (−11.7k)
119
+ 14:32:07 · Δ 3m12s · opencode-go/deepseek-v4.1-flash max · in 85.4k (1.62M), cached 1.53M, out 3.7k, cost $0.21 · sess in 2.1M (14.5M), cached 12.4M, out 88k, cost $1.90 · ⚠ cache expired (−11.7k)
119
120
  ```
120
121
 
121
122
  | Segment | Meaning |
122
123
  | --- | --- |
123
124
  | `14:32:07` | When the response ended (`completed`, else `streamed`, else `created`). |
124
125
  | `Δ 3m12s` | Time since the previous prompt of the same session. |
125
- | `orcarouter-dsv4.1-flash-free` | The endpoint that served the turn (`identity: "endpoint"`, the default): the gateway names it in a response header, or the request host names the operator. Without one the segment falls back to `providerID/modelID` (variant as a trailing word); `identity: "model"` always shows that form. Yellow with `changed` when it differs from the previous prompt. |
126
- | `in 85.4k (1.62M), cached 1.53M, out 3.7k` | `in` is the uncached part of the prompt (fresh input + cache writes), the parenthesised value the whole prompt — shown only when the two differ — `cached` its cached part, and `out` everything generated (visible output + reasoning). With several steps the segment reads `3 steps · …` and reports the step the turn ended with (`latest`); `turnTotals: "sum"` adds every step instead. |
127
- | `sess in 2.1M (14.5M), cached 12.4M, out 88k` | The session totals reported by the host, in the same buckets. |
126
+ | `opencode-go/deepseek-v4.1-flash max` | The identity of the turn: the provider the model ran through, as OpenCode is configured, and the model (the variant as a trailing word; `fields.model`/`fields.variant` hide either). Yellow with `changed` when the provider differs from the previous prompt, `model changed` when only the model does. |
127
+ | `in 85.4k (1.62M), cached 1.53M, out 3.7k, cost $0.21` | `in` is the uncached part of the prompt (fresh input + cache writes), the parenthesised value the whole prompt — shown only when the two differ — `cached` its cached part, `out` everything generated (visible output + reasoning), and `cost` what the turn was billed. With several steps the segment reads `3 steps · …` and reports the step the turn ended with (`latest`) for the tokens, while the cost is always the turn's own — every step is paid for; `turnTotals: "sum"` adds every step's tokens instead. |
128
+ | `cost $0.21` | Money, not tokens: a turn sums every step's cost whatever the token view shows. A cost of zero is left out, so a free model reads as free. `fields.cost: false` hides it. |
129
+ | `sess in 2.1M (14.5M), cached 12.4M, out 88k, cost $1.90` | The session totals reported by the host, in the same buckets, with the cost of the whole session. |
128
130
  | `⚠ cache expired (−11.7k)` | Yellow. The prompt cache read fell by that many tokens against a comparable previous step; `×N` when several steps in the turn lost cache. |
129
131
 
130
132
  The turn segment carries no label by default — the numbers are the turn's, and
@@ -146,7 +148,7 @@ and any argument — including an unknown token, which is ignored — keeps it o
146
148
  There is no default key binding — the command is palette-only, so it never
147
149
  shadows a key you use.
148
150
 
149
- ![The /usage endpoints view](docs/images/panel-endpoints.png)
151
+ ![The /usage providers view](docs/images/panel-providers.png)
150
152
 
151
153
  The view bar at the top names every view and brackets the active one; `?` opens
152
154
  a help overlay that repeats the keys and defines every number.
@@ -157,14 +159,14 @@ a help overlay that repeats the keys and defines every number.
157
159
  | --- | --- |
158
160
  | `↑` `↓` / `j` `k` | Move the cursor; the row under it is highlighted. |
159
161
  | `pageup` `pagedown` / `home` `end` | Move by ten rows / to the first or last row. |
160
- | `enter` | Drill into the row: a model → the endpoints that served it and its affinity; an endpoint → the models it served and its latency; a session → its turns; a period → the models of the period. In `db`, prune the steps recorded before the selected retention's cutoff date (asks first). |
162
+ | `enter` | Drill into the row: a model → the providers it ran through and their latency; a provider → the models it served and its latency; a session → its turns; a period → the providers of the period. In `db`, prune the steps recorded before the selected retention's cutoff date (asks first). |
161
163
  | `backspace` | Go back from a drill-down. |
162
- | `0`–`9` / `[` `]` | Pick a view (`0` is `db`) / cycle views. |
164
+ | `1`–`9` / `[` `]` | Pick a view (`9` is `db`) / cycle views. |
163
165
  | `t` / `shift+t` | Next / previous range. |
164
166
  | `s` / `shift+s` | Cycle the sort column / reverse it. |
165
167
  | `b` | `periods` bucket: day → week → month. |
166
168
  | `a` | `turns` scope: this session ↔ every session. |
167
- | `m` `e` | Filter by model or by **endpoint** (a picker of the values actually observed). |
169
+ | `m` `p` | Filter by model or by **provider** (a picker of the values actually observed). |
168
170
  | `x` | Clear the filters. |
169
171
  | `r` | Re-read the database. |
170
172
  | `v` | `db`: compact the file, giving the space of deleted rows back. |
@@ -178,13 +180,12 @@ durable storage, so the panel reopens where it was left.
178
180
 
179
181
  | View | Answers |
180
182
  | --- | --- |
181
- | `overview` | Steps, sessions, prompts, `in`/`cached`/`write`/`out`, `hit`, cost, an activity sparkline, a `this session` block and a **data coverage** block (how many steps lack a model, an endpoint or a completion — a zero elsewhere is only trustworthy when this is complete). |
182
- | `models` | Every model with its cache (`hit` and the per-step `hit p50`), tokens, cost, the **endpoints that actually served it** and how often its identity changed. `enter` opens the per-endpoint detail. |
183
- | `endpoints` | **Who served the work**: one row per routing endpoint, with the models it served, steps, share, prompt, cached, `hit`, p50 throughput, wall time and cost. `enter` lists every model it served. A request whose endpoint was never observed is dimmed — the panel does not invent an identity. |
184
- | `affinity` | How often the step's identity changed against the step before it in the same session — the model and the endpoint — the cache those changes cost, and the most frequent transitions. |
185
- | `cache` | Reuse by model, losses grouped by reason (`expired`, `compaction`, `unknown`), **cache survival against idle time**, reuse kept per endpoint, the observed TTL bounds (`hits up to` / `drops from`) and the most recent losses. |
186
- | `periods` | Day, week or month totals — steps, sessions, `in`, `cached`, `write`, `hit`, `out`, cost — with a sparkline per metric and a totals row. `enter` lists the models of a period. |
187
- | `latency` | Wall time, streaming window and throughput as p50/p90/p99 overall and per model (per endpoint when a model is filtered). `n < 5` is dimmed. |
183
+ | `overview` | Steps, sessions, prompts, `in`/`cached`/`write`/`out`, `hit`, cost, an activity sparkline, a `this session` block and a **data coverage** block (how many models and providers were observed, and how many steps lack a model or a completion — a zero elsewhere is only trustworthy when this is complete). |
184
+ | `models` | Every model with its cache (`hit` and the per-step `hit p50`), tokens, cost, the **providers it ran through** and how often it switched model or provider — with the cache a provider switch cost. `enter` opens the per-provider detail. |
185
+ | `providers` | **Who ran the work**: one row per provider, with the models it served, steps, share, prompt, cached, `hit`, p50 throughput, wall time and cost. `enter` lists every model it served. Steps recorded without a provider (a model that was never observed) are dimmed and cannot be drilled into. |
186
+ | `cache` | Reuse by model, losses grouped by reason (`expired`, `compaction`, `unknown`), **cache survival against idle time**, reuse kept per provider, the observed TTL bounds (`hits up to` / `drops from`) and the most recent losses. |
187
+ | `periods` | Day, week or month totals — steps, sessions, `in`, `cached`, `write`, `hit`, `out`, cost — with a sparkline per metric and a totals row. `enter` lists the providers of a period. |
188
+ | `latency` | Wall time, streaming window and throughput as p50/p90/p99 overall and per model (per provider when a model is filtered). `n < 5` is dimmed. |
188
189
  | `sessions` | Each session with steps, prompts, tokens, `hit`, cost, its directory and how many models it used; subagent sessions are indented under their parent and rolled up. |
189
190
  | `turns` | The per-prompt history: one line per finished turn, rendered exactly like the live line. `a` widens it to every session, titled. |
190
191
  | `db` | Where the file lives, what it holds and how much of it is old. The retention table lists, per preset (`30`/`90`/`365` days), how many steps a prune would remove and the cutoff date it prunes from — pick one with `↑`/`↓` and `enter` prunes it (a confirmation first); `v` gives the space back. |
@@ -194,24 +195,27 @@ read in one place means the same in the other: `prompt` is everything the
194
195
  provider saw (`cached + fresh + writes`), `in` the uncached part, `hit` is
195
196
  `cached / prompt`, and `out` everything generated (visible output + reasoning).
196
197
 
197
- The endpoint is what the gateway names in `x-opencode-endpoint-id`, or the host
198
- of a per-operator provider. A **gateway host is not an endpoint**: when the
199
- gateway names no downstream endpoint, the request has no observed endpoint and
200
- the views say so (`– (never observed)`) instead of showing the gateway's name as
201
- if it had run the model. The line and the sidebar then fall back to
202
- `provider/model`. The line reports the endpoint of the turn it belongs to: a
203
- turn the gateway did not name falls back even when an earlier turn of the same
204
- provider and model had an endpoint.
198
+ The identity of a step is the **provider the model ran through** — `opencode`,
199
+ `opencode-go`, `deepseek`, whatever the provider is called in the OpenCode
200
+ configuration — and the model itself. That is what every view groups by, and it
201
+ is also the whole answer available: a gateway such as OpenCode Console may
202
+ re-route a request to another operator, but that upstream is not observable from
203
+ the plugin, and the identity a request *would* have been routed to is not
204
+ evidence of who ran it. The provider is: the same model through `deepseek` and
205
+ through `opencode-go` are two rows, two caches and two latency profiles, and a
206
+ switch between them forfeits the cache the previous one held (the switch counts
207
+ and the cache losses in the `models` view count exactly that).
205
208
 
206
209
  `tps`/`wall`/`stream` are produced tokens per streaming second / request to
207
210
  completed step / request to the last chunk. The sidebar's rate (per turn, and
208
211
  the session average on its totals) is the **weighted** one — produced tokens
209
212
  divided by the summed streaming windows — so it answers "how fast did this
210
213
  produce"; the `latency` view reports the p50 of the per-step rates instead, which
211
- answers "how fast is a typical step". A change of identity is not by
212
- itself a fault — a gateway may re-route deliberately — so `affinity` pairs the
213
- count with the cache reuse it actually cost. The panel's `?` overlay defines
214
- every number in place.
214
+ answers "how fast is a typical step". A switch from one step to the next is not
215
+ by itself a fault — moving to another model or provider is a deliberate choice —
216
+ so the `models` view pairs the count with the cache the switch actually cost,
217
+ which only a provider switch can: two models never share a cache to lose. The
218
+ panel's `?` overlay defines every number in place.
215
219
 
216
220
  ## Configuration
217
221
 
@@ -225,7 +229,6 @@ Options apply to both entries (each side reads the ones it needs):
225
229
  | `sidebar` | `true` | Show the session summary and the per-prompt history — cache hit and cost per turn — in the session sidebar (the slot is invisible while the sidebar is hidden). |
226
230
  | `sidebarTurns` | `5` | How many turns the sidebar history shows. |
227
231
  | `panel` | `true` | Show the `/usage` statistics panel and its command. `false` keeps the line and the sidebar. |
228
- | `identity` | `"endpoint"` | Which identity the line leads with: `endpoint` shows the endpoint that served the turn (falling back to `provider/model`); `model` always shows `provider/model#variant`. |
229
232
  | `fields` | see below | Toggle line segments. |
230
233
  | `labels` | see below | Override line labels (the plugin is English-only by default). |
231
234
 
@@ -234,7 +237,7 @@ Options apply to both entries (each side reads the ones it needs):
234
237
  ```jsonc
235
238
  {
236
239
  "options": {
237
- "fields": { "clock": true, "delta": true, "model": true, "variant": true, "turn": true, "session": true, "reasoning": false, "cost": false, "cacheExpiry": true },
240
+ "fields": { "clock": true, "delta": true, "model": true, "variant": true, "turn": true, "session": true, "reasoning": false, "cost": true, "cacheExpiry": true },
238
241
  "turnTotals": "latest",
239
242
  "labels": { "delta": "Δ", "turn": "", "session": "sess", "step": "step", "steps": "steps", "input": "in", "cached": "cached", "output": "out", "reasoning": "reason", "cost": "cost", "cacheExpired": "cache expired", "providerChanged": "changed", "modelChanged": "model changed" }
240
243
  }
@@ -260,11 +263,11 @@ option overrides both. The file is private to the user: its directory is created
260
263
  through a read-only connection, so it can never write, migrate or take the
261
264
  recorder's lock.
262
265
 
263
- Per step the database holds tokens, cost, timings, finish reason, the
264
- provider/model it ran as, the endpoint label, and the session title and working
265
- directory. **Prompts and responses are not stored**, and nothing leaves the
266
- machine. The schema, the indexes, the endpoint-discovery rules and the security
267
- notes live in [docs/internals.md](docs/internals.md).
266
+ Per step the database holds tokens, cost, timings, finish reason, the provider
267
+ and the model it ran as, and the session title and working directory. **Prompts
268
+ and responses are not stored**, and nothing leaves the machine. The schema, the
269
+ indexes, the identity rules and the security notes live in
270
+ [docs/internals.md](docs/internals.md).
268
271
 
269
272
  ## CLI report
270
273
 
@@ -274,9 +277,9 @@ From a checkout, the database can be read without opening the TUI:
274
277
  bun run report # overview over all time
275
278
  bun run report models 7d # one view, one range
276
279
  bun run report all # every view
277
- bun run report endpoints --model deepseek-v4.1-flash-free
280
+ bun run report providers --model deepseek-v4.1-flash
278
281
  bun run report periods --granularity month
279
- bun run report affinity --endpoint orcarouter-dsv4.1flash
282
+ bun run report models --provider opencode-go
280
283
  bun run report --json # raw rows and every analysis, for scripting
281
284
  bun run report --ndjson > backup.jsonl # export the whole database
282
285
  bun run report --import backup.jsonl # merge an export (idempotent)
@@ -285,7 +288,7 @@ bun run report --help
285
288
 
286
289
  The views come from the same `buildPanel` the TUI renders, so the terminal and
287
290
  the panel never drift apart. `--width`, `--granularity`, `--model`,
288
- `--endpoint`, `--sort` and `--asc` mirror what the panel's keys do.
291
+ `--provider`, `--sort` and `--asc` mirror what the panel's keys do.
289
292
 
290
293
  ## Development
291
294
 
@@ -302,7 +305,8 @@ bun run docs:images # re-render docs/images/*.png (needs ImageMagick)
302
305
  turn accounting, the host-shape adapter, the view models, and the database,
303
306
  queries and analysis layer. No host imports, so they are unit-testable without
304
307
  a TUI runtime.
305
- - `src/endpoint.ts`, `src/text.ts` — endpoint discovery and text hygiene.
308
+ - `src/text.ts` — text hygiene and the token shape a provider id is validated
309
+ against.
306
310
  - `src/recorder.ts` — the event-stream state machine that fills the database.
307
311
  - `src/panel-build.ts`, `src/panel.tsx`, `src/sidebar.tsx` — panel assembly, the
308
312
  panel component, and the sidebar contribution.
package/dist/core.d.ts CHANGED
@@ -78,15 +78,6 @@ export type TurnStats = {
78
78
  providerID: string | undefined;
79
79
  modelID: string | undefined;
80
80
  variant: string | undefined;
81
- /** Gateway routing endpoint that served the turn, when a source identifies it. */
82
- router: string | undefined;
83
- /**
84
- * The displayed identity differs from the previous turn's. The TUI fills it
85
- * in (the transcript carries no routing information); the line warns with the
86
- * same `changed` marker it uses for a provider switch.
87
- */
88
- identityChanged: boolean;
89
- affinityKey: string | undefined;
90
81
  /** Provider ID differs from the previous turn in the same transcript. */
91
82
  providerChanged: boolean;
92
83
  /** Provider is the same but the model or variant differs. */
@@ -105,13 +96,6 @@ export type TurnStats = {
105
96
  cacheExpired: boolean;
106
97
  /** Assistant steps in the turn. */
107
98
  steps: number;
108
- /**
109
- * Message ids of the settled steps of the turn, oldest first. The TUI looks
110
- * up the endpoint the recorder stored for these steps, so the line reports
111
- * who served *this* turn: a lookup by provider and model alone would tag a
112
- * turn with the endpoint of an older one.
113
- */
114
- stepIDs: string[];
115
99
  };
116
100
  export type TurnSegment = {
117
101
  assistants: AssistantMessage[];
@@ -141,16 +125,29 @@ export declare function tokenCounts(message: AssistantMessage): {
141
125
  write: number;
142
126
  };
143
127
  export declare function totalize(steps: readonly AssistantMessage[]): Totals;
144
- export declare function affinityKey(model: ModelRefLike | undefined): string | undefined;
128
+ /**
129
+ * The identity of a model reference: the provider it runs through, the model
130
+ * and its variant. Two steps with the same key ran the same thing the same way,
131
+ * which is what `modelChanged` compares.
132
+ */
133
+ export declare function identityKey(model: ModelRefLike | undefined): string | undefined;
145
134
  export declare function cacheRead(message: AssistantMessage | undefined): number;
146
135
  export declare function stepCreated(message: AssistantMessage | undefined): number | undefined;
147
136
  export declare function stepEnd(message: AssistantMessage | undefined): number | undefined;
137
+ /**
138
+ * Which identity the two steps must share for a reuse loss to be measurable.
139
+ * `provider` is the strict one: two providers are two caches, so a switch
140
+ * between them is not a loss but a different cache. `model` drops that test,
141
+ * for the reports that measure what an identity change costs: forfeiting the
142
+ * previous provider's cache is exactly the cost they report.
143
+ */
144
+ export type CacheDropScope = "provider" | "model";
148
145
  /**
149
146
  * Cache reuse loss against a reference step, mirroring OpenCode's own
150
147
  * `turn-usage` heuristic: only comparable when the model is identical, and
151
- * OpenAI's endpoint reports small reads that are not worth flagging.
148
+ * OpenAI's API reports small reads that are not worth flagging.
152
149
  */
153
- export declare function cacheDrop(reference: AssistantMessage | undefined, current: AssistantMessage): number | undefined;
150
+ export declare function cacheDrop(reference: AssistantMessage | undefined, current: AssistantMessage, scope?: CacheDropScope): number | undefined;
154
151
  /** Milliseconds between a reference step's completion and the next request. */
155
152
  export declare function stepGap(reference: AssistantMessage | undefined, current: AssistantMessage): number | undefined;
156
153
  /**
@@ -179,13 +176,14 @@ export declare function stepTps(message: AssistantMessage): number | undefined;
179
176
  export declare function isSettledStep(message: AssistantMessage): boolean;
180
177
  /**
181
178
  * Compute the stats of the most recent turn in a transcript, including the
182
- * comparison against the previous turn (affinity and cache reuse).
179
+ * comparison against the previous turn (a provider or model switch, and cache
180
+ * reuse).
183
181
  *
184
182
  * Returns undefined while the newest turn is still being generated: the line
185
183
  * appears when a turn ends, never with the zeroes of an in-flight response.
186
184
  */
187
185
  export declare function computeTurn(messages: readonly TranscriptMessage[], session?: Totals): TurnStats | undefined;
188
- /** True when a cache drop is small enough to be endpoint noise. */
186
+ /** True when a cache drop is small enough to be provider noise. */
189
187
  export declare function isNoiseDrop(providerID: string | undefined, drop: number): boolean;
190
188
  export type LineTone = "base" | "muted" | "warning";
191
189
  export type LineSegment = {
@@ -214,14 +212,6 @@ export type LineLabels = {
214
212
  * tool-call loop re-sends (and re-reads) the same context once per step.
215
213
  */
216
214
  export type TurnTotalsView = "latest" | "sum";
217
- /**
218
- * Which identity the line leads with. `endpoint` shows the gateway endpoint
219
- * that served the turn (`orcarouter-dsv4.1flash`) when a recorder learned one,
220
- * falling back to `provider/model`; `model` always shows `provider/model`.
221
- * The same provider and model can be routed to different endpoints per request,
222
- * so the endpoint is the identity a change is measured against.
223
- */
224
- export type LineIdentity = "endpoint" | "model";
225
215
  export type LineFields = {
226
216
  clock: boolean;
227
217
  delta: boolean;
@@ -261,11 +251,9 @@ export declare function formatLineSegments(stats: TurnStats, options?: {
261
251
  labels?: Partial<LineLabels>;
262
252
  fields?: Partial<LineFields>;
263
253
  turnTotals?: TurnTotalsView;
264
- identity?: LineIdentity;
265
254
  }): LineSegment[];
266
255
  export declare function formatLine(stats: TurnStats, options?: {
267
256
  labels?: Partial<LineLabels>;
268
257
  fields?: Partial<LineFields>;
269
258
  turnTotals?: TurnTotalsView;
270
- identity?: LineIdentity;
271
259
  }): string;
package/dist/index.d.ts CHANGED
@@ -4,9 +4,11 @@ import { Plugin } from "@opencode/plugin";
4
4
  * every assistant step, prompt and lifecycle event into the stats database;
5
5
  * the TUI entry reads the same database for its live line and stats panel.
6
6
  *
7
- * The plugin is observational: it never rewrites prompts, requests or
8
- * responses, and a failure inside the recorder is swallowed so a session can
9
- * never be interrupted by its own telemetry.
7
+ * Everything the recorder stores comes from the event stream — the provider
8
+ * and model a step ran as, the tokens and the timing. The plugin is
9
+ * observational: it never rewrites prompts, requests or responses, registers
10
+ * no hook on the request path, and a failure inside the recorder is swallowed
11
+ * so a session can never be interrupted by its own telemetry.
10
12
  */
11
13
  export type Options = {
12
14
  /** Turn recording off: no event subscription, no database. */