opencode-tps-meter 0.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/README.md +594 -0
- package/dist/config.d.ts +46 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/constants.d.ts +43 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +832 -0
- package/dist/index.mjs +786 -0
- package/dist/tokenCounter.d.ts +85 -0
- package/dist/tokenCounter.d.ts.map +1 -0
- package/dist/tracker.d.ts +17 -0
- package/dist/tracker.d.ts.map +1 -0
- package/dist/types.d.ts +322 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/ui.d.ts +18 -0
- package/dist/ui.d.ts.map +1 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# OpenCode TPS Meter
|
|
4
|
+
|
|
5
|
+
**Real-time AI token throughput visualization for OpenCode**
|
|
6
|
+
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
[](https://bun.sh)
|
|
9
|
+
[](https://opencode.ai)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
╔══════════════════════════════════════════════════╗
|
|
16
|
+
║ TPS: 92.4 (avg 78.1) | tokens: 1,842 ║
|
|
17
|
+
╚══════════════════════════════════════════════════╝
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
A live tokens-per-second meter plugin for OpenCode. Track AI token throughput in real-time with a configurable rolling window display. Only tracks **assistant role** messages — user and system messages are automatically excluded from metrics. File parts are also excluded from token counting.
|
|
21
|
+
|
|
22
|
+
> **Note:** Time display is disabled by default. Enable with `showElapsed: true` in configuration.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Features
|
|
27
|
+
|
|
28
|
+
- **Real-time Monitoring** — Live TPS calculation with configurable rolling window
|
|
29
|
+
- **Smart Filtering** — Tracks only assistant text/reasoning, excludes user prompts, tools, patches, snapshots, and files
|
|
30
|
+
- **Noise Suppression** — TPS display starts after 250ms of assistant output to avoid spikes
|
|
31
|
+
- **Multi-Session Support** — Isolated tracking per session with automatic cleanup
|
|
32
|
+
- **Throttled UI Updates** — Configurable update intervals to prevent UI flooding
|
|
33
|
+
- **Optional Time Display** — Elapsed time display (disabled by default, enable with `showElapsed: true`)
|
|
34
|
+
- **TPS-Based Color Coding** — Visual feedback with color-coded toasts (red/yellow/green) based on throughput speed
|
|
35
|
+
- **Dual Display Modes** — TUI toast notifications with fallback to client.toast
|
|
36
|
+
- **Zero Console Logging** — Safe for TUI environments (no console.* calls)
|
|
37
|
+
- **Dual Format** — ESM and CommonJS builds for maximum compatibility
|
|
38
|
+
- **Heuristic Token Counting** — Fast approximation without heavy dependencies
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
This plugin is designed for local installation. Since it's not published to npm, install it from the local directory or git repository:
|
|
45
|
+
|
|
46
|
+
### From Local Directory
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Clone or download the repository
|
|
50
|
+
cd opencode-tps-meter
|
|
51
|
+
|
|
52
|
+
# Install dependencies and build
|
|
53
|
+
bun install
|
|
54
|
+
bun run build
|
|
55
|
+
|
|
56
|
+
# Link for local development
|
|
57
|
+
bun link
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Then in your OpenCode project:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Link the plugin locally
|
|
64
|
+
bun link opencode-tps-meter
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### From Git Repository
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Install directly from git
|
|
71
|
+
bun add github:ChiR24/opencode-tps-meter
|
|
72
|
+
|
|
73
|
+
# Or with npm
|
|
74
|
+
npm install github:ChiR24/opencode-tps-meter
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Manual Installation
|
|
78
|
+
|
|
79
|
+
Copy the `dist` folder from this repository into your project's `node_modules/opencode-tps-meter` directory.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Quick Start
|
|
84
|
+
|
|
85
|
+
> **Prerequisites:** Make sure you've built the plugin first:
|
|
86
|
+
> ```bash
|
|
87
|
+
> bun install
|
|
88
|
+
> bun run build
|
|
89
|
+
> ```
|
|
90
|
+
|
|
91
|
+
### As OpenCode Plugin (Recommended)
|
|
92
|
+
|
|
93
|
+
Create a plugin file in your OpenCode project:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// File: tps-meter-plugin.ts (or .js)
|
|
97
|
+
import TpsMeterPlugin from 'opencode-tps-meter';
|
|
98
|
+
|
|
99
|
+
// Export the plugin - it automatically hooks into OpenCode events
|
|
100
|
+
export default TpsMeterPlugin;
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Then configure it in your OpenCode config (see Configuration section below).
|
|
104
|
+
|
|
105
|
+
### Programmatic Usage
|
|
106
|
+
|
|
107
|
+
For standalone usage (outside of OpenCode plugin context), import from the source files directly:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
// Import from source files (for development/bundler setups)
|
|
111
|
+
import { createTracker } from 'opencode-tps-meter/src/tracker.js';
|
|
112
|
+
import { createUIManager } from 'opencode-tps-meter/src/ui.js';
|
|
113
|
+
import { createTokenizer, countTokens } from 'opencode-tps-meter/src/tokenCounter.js';
|
|
114
|
+
import type { OpenCodeClient } from '@opencode-ai/plugin';
|
|
115
|
+
|
|
116
|
+
// Or from the built dist files
|
|
117
|
+
import { createTracker } from 'opencode-tps-meter/dist/tracker.js';
|
|
118
|
+
import { createUIManager } from 'opencode-tps-meter/dist/ui.js';
|
|
119
|
+
import { createTokenizer } from 'opencode-tps-meter/dist/tokenCounter.js';
|
|
120
|
+
|
|
121
|
+
// Initialize components
|
|
122
|
+
const tracker = createTracker({
|
|
123
|
+
sessionId: 'my-session',
|
|
124
|
+
rollingWindowMs: 2000 // 2-second rolling window
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const ui = createUIManager(client, {
|
|
128
|
+
updateIntervalMs: 50,
|
|
129
|
+
format: 'compact',
|
|
130
|
+
showAverage: true,
|
|
131
|
+
showInstant: true,
|
|
132
|
+
showTotalTokens: true,
|
|
133
|
+
showElapsed: false
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const tokenizer = createTokenizer('heuristic');
|
|
137
|
+
|
|
138
|
+
// Process streaming tokens
|
|
139
|
+
async function processStream(stream: AsyncIterable<string>) {
|
|
140
|
+
for await (const chunk of stream) {
|
|
141
|
+
const tokenCount = tokenizer.count(chunk);
|
|
142
|
+
tracker.recordTokens(tokenCount);
|
|
143
|
+
|
|
144
|
+
ui.updateDisplay(
|
|
145
|
+
tracker.getInstantTPS(),
|
|
146
|
+
tracker.getAverageTPS(),
|
|
147
|
+
tracker.getTotalTokens(),
|
|
148
|
+
tracker.getElapsedMs()
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Show final stats
|
|
153
|
+
ui.showFinalStats(
|
|
154
|
+
tracker.getTotalTokens(),
|
|
155
|
+
tracker.getAverageTPS(),
|
|
156
|
+
tracker.getElapsedMs()
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Note:** When using the plugin with OpenCode, you only need the default export. The programmatic API is for advanced use cases where you want to use the TPS tracking components separately.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Configuration
|
|
166
|
+
|
|
167
|
+
Configuration is loaded from multiple sources in priority order (highest to lowest):
|
|
168
|
+
|
|
169
|
+
1. **Environment Variables** (`TPS_METER_*`)
|
|
170
|
+
2. **Global Config** (`~/.config/opencode/tps-meter.json`)
|
|
171
|
+
3. **Project Config** (`.opencode/tps-meter.json`)
|
|
172
|
+
4. **Built-in Defaults**
|
|
173
|
+
|
|
174
|
+
> **Note:** Later sources override earlier ones. Environment variables have the highest priority and override all config files. Project config overrides global config.
|
|
175
|
+
|
|
176
|
+
### Environment Variables
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# Core settings
|
|
180
|
+
TPS_METER_ENABLED=true # Enable/disable plugin
|
|
181
|
+
TPS_METER_UPDATE_INTERVAL_MS=50 # UI update throttle (ms)
|
|
182
|
+
TPS_METER_ROLLING_WINDOW_MS=1000 # TPS calculation window (ms)
|
|
183
|
+
TPS_METER_FORMAT=compact # compact | verbose | minimal
|
|
184
|
+
TPS_METER_MIN_VISIBLE_TPS=0 # Minimum TPS to display
|
|
185
|
+
|
|
186
|
+
# Display toggles
|
|
187
|
+
TPS_METER_SHOW_AVERAGE=true
|
|
188
|
+
TPS_METER_SHOW_INSTANT=true
|
|
189
|
+
TPS_METER_SHOW_TOTAL_TOKENS=true
|
|
190
|
+
TPS_METER_SHOW_ELAPSED=false
|
|
191
|
+
|
|
192
|
+
# Token counting heuristic
|
|
193
|
+
TPS_METER_FALLBACK_HEURISTIC=chars_div_4 # chars_div_4 | chars_div_3 | words_div_0_75
|
|
194
|
+
|
|
195
|
+
# Color coding (visual feedback based on TPS speed)
|
|
196
|
+
TPS_METER_ENABLE_COLOR_CODING=false # Enable color-coded toasts
|
|
197
|
+
TPS_METER_SLOW_TPS_THRESHOLD=10 # Below this = red (slow)
|
|
198
|
+
TPS_METER_FAST_TPS_THRESHOLD=50 # Above this = green (fast)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### JSON Configuration
|
|
202
|
+
|
|
203
|
+
Create `.opencode/tps-meter.json` in your project root:
|
|
204
|
+
|
|
205
|
+
```json
|
|
206
|
+
{
|
|
207
|
+
"enabled": true,
|
|
208
|
+
"updateIntervalMs": 50,
|
|
209
|
+
"rollingWindowMs": 1000,
|
|
210
|
+
"showAverage": true,
|
|
211
|
+
"showInstant": true,
|
|
212
|
+
"showTotalTokens": true,
|
|
213
|
+
"showElapsed": false,
|
|
214
|
+
"format": "compact",
|
|
215
|
+
"minVisibleTps": 0,
|
|
216
|
+
"fallbackTokenHeuristic": "chars_div_4",
|
|
217
|
+
"enableColorCoding": false,
|
|
218
|
+
"slowTpsThreshold": 10,
|
|
219
|
+
"fastTpsThreshold": 50
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
#### Enable Time Display
|
|
224
|
+
|
|
225
|
+
To show elapsed time in the meter:
|
|
226
|
+
|
|
227
|
+
```json
|
|
228
|
+
{
|
|
229
|
+
"showElapsed": true,
|
|
230
|
+
"format": "compact"
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Output: `TPS: 92.4 (avg 78.1) | tokens: 1,842 | 00:23`
|
|
235
|
+
|
|
236
|
+
### Default Configuration
|
|
237
|
+
|
|
238
|
+
| Option | Type | Default | Description |
|
|
239
|
+
|--------|------|---------|-------------|
|
|
240
|
+
| `enabled` | `boolean` | `true` | Enable/disable the plugin |
|
|
241
|
+
| `updateIntervalMs` | `number` | `50` | UI update interval in milliseconds |
|
|
242
|
+
| `rollingWindowMs` | `number` | `1000` | Rolling window for TPS calculation |
|
|
243
|
+
| `showAverage` | `boolean` | `true` | Show average TPS in display |
|
|
244
|
+
| `showInstant` | `boolean` | `true` | Show instantaneous TPS in display |
|
|
245
|
+
| `showTotalTokens` | `boolean` | `true` | Show total token count |
|
|
246
|
+
| `showElapsed` | `boolean` | `false` | Show elapsed time |
|
|
247
|
+
| `format` | `string` | `"compact"` | Display format: `compact`, `verbose`, `minimal` |
|
|
248
|
+
| `minVisibleTps` | `number` | `0` | Minimum TPS value to trigger display |
|
|
249
|
+
| `fallbackTokenHeuristic` | `string` | `"chars_div_4"` | Token counting method |
|
|
250
|
+
| `enableColorCoding` | `boolean` | `false` | Enable TPS-based color coding |
|
|
251
|
+
| `slowTpsThreshold` | `number` | `10` | TPS below this shows red (slow) |
|
|
252
|
+
| `fastTpsThreshold` | `number` | `50` | TPS above this shows green (fast) |
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Color Coding
|
|
257
|
+
|
|
258
|
+
Enable visual feedback with color-coded toasts based on token throughput speed:
|
|
259
|
+
|
|
260
|
+
```json
|
|
261
|
+
{
|
|
262
|
+
"enableColorCoding": true,
|
|
263
|
+
"slowTpsThreshold": 10,
|
|
264
|
+
"fastTpsThreshold": 50
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
| Color | TPS Range | Meaning |
|
|
269
|
+
|-------|-----------|---------|
|
|
270
|
+
| 🔴 **Red** | Below `slowTpsThreshold` | Slow generation |
|
|
271
|
+
| 🟡 **Yellow** | Between thresholds | Medium speed |
|
|
272
|
+
| 🟢 **Green** | Above `fastTpsThreshold` | Fast generation |
|
|
273
|
+
| 🟢 **Green** | Final stats | Message complete |
|
|
274
|
+
|
|
275
|
+
**Note:** Color coding requires TUI toast methods (`client.tui.showToast` or `client.tui.publish`). The fallback `client.toast` methods only support info/success variants.
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Display Formats
|
|
280
|
+
|
|
281
|
+
### Compact (Default)
|
|
282
|
+
```
|
|
283
|
+
TPS: 92.4 (avg 78.1) | tokens: 1,842
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Compact with Time (showElapsed: true)
|
|
287
|
+
```
|
|
288
|
+
TPS: 92.4 (avg 78.1) | tokens: 1,842 | 00:23
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Verbose
|
|
292
|
+
```
|
|
293
|
+
TPS Meter — Instant: 92.4 tokens/sec | Average: 78.1 tokens/sec | Total: 1,842 tokens
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Verbose with Time (showElapsed: true)
|
|
297
|
+
```
|
|
298
|
+
TPS Meter — Instant: 92.4 tokens/sec | Average: 78.1 tokens/sec | Total: 1,842 tokens | Duration: 23s
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Minimal
|
|
302
|
+
```
|
|
303
|
+
92.4 TPS (1,842 tokens)
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## API Reference
|
|
309
|
+
|
|
310
|
+
**Prerequisite:** Build the plugin first to generate the `dist/` folder:
|
|
311
|
+
```bash
|
|
312
|
+
cd opencode-tps-meter
|
|
313
|
+
bun install
|
|
314
|
+
bun run build
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### `createTracker(options?)`
|
|
318
|
+
|
|
319
|
+
Factory function that creates a TPS tracker with rolling window calculation using a ring buffer (max 100 entries).
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
import { createTracker } from 'opencode-tps-meter/dist/tracker.js';
|
|
323
|
+
|
|
324
|
+
interface TPSTrackerOptions {
|
|
325
|
+
sessionId?: string; // Optional session identifier
|
|
326
|
+
rollingWindowMs?: number; // Window duration (default: 2000ms)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const tracker = createTracker({
|
|
330
|
+
sessionId: 'my-session',
|
|
331
|
+
rollingWindowMs: 2000
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// Methods
|
|
335
|
+
tracker.recordTokens(count: number, timestamp?: number): void
|
|
336
|
+
tracker.getInstantTPS(): number // TPS over rolling window
|
|
337
|
+
tracker.getAverageTPS(): number // TPS over entire session
|
|
338
|
+
tracker.getTotalTokens(): number // Total tokens recorded
|
|
339
|
+
tracker.getElapsedMs(): number // Elapsed time in ms
|
|
340
|
+
tracker.getSessionId(): string | undefined // Session identifier
|
|
341
|
+
tracker.getBufferSize(): number // Current buffer entries
|
|
342
|
+
tracker.getMaxBufferSize(): number // Max buffer capacity (100)
|
|
343
|
+
tracker.getWindowMs(): number // Rolling window duration
|
|
344
|
+
tracker.reset(): void // Reset all tracking data
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### `createUIManager(client, config)`
|
|
348
|
+
|
|
349
|
+
Factory function that creates a UI manager with throttled display updates and automatic fallback.
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
import { createUIManager } from 'opencode-tps-meter/dist/ui.js';
|
|
353
|
+
|
|
354
|
+
const ui = createUIManager(client, {
|
|
355
|
+
updateIntervalMs: 50,
|
|
356
|
+
format: 'compact',
|
|
357
|
+
showAverage: true,
|
|
358
|
+
showInstant: true,
|
|
359
|
+
showTotalTokens: true,
|
|
360
|
+
showElapsed: false
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
// Methods
|
|
364
|
+
ui.updateDisplay(instantTps, avgTps, totalTokens, elapsedMs): void
|
|
365
|
+
ui.showFinalStats(totalTokens, avgTps, elapsedMs): void // Immediate display
|
|
366
|
+
ui.clear(): void // Cleanup resources
|
|
367
|
+
ui.setUpdateInterval(ms: number): void // Change throttle
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
**Display Priority:**
|
|
371
|
+
1. `client.tui.showToast()` — Primary method
|
|
372
|
+
2. `client.tui.publish()` — Fallback for TUI events
|
|
373
|
+
3. `client.toast.info/success()` — Final fallback
|
|
374
|
+
|
|
375
|
+
### `createTokenizer(type?)`
|
|
376
|
+
|
|
377
|
+
Factory function for heuristic token counters.
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
import { createTokenizer } from 'opencode-tps-meter/dist/tokenCounter.js';
|
|
381
|
+
|
|
382
|
+
// Available types
|
|
383
|
+
const tokenizer = createTokenizer('heuristic'); // Math.ceil(chars / 4) - Default
|
|
384
|
+
const tokenizer = createTokenizer('word'); // Math.ceil(words / 0.75)
|
|
385
|
+
const tokenizer = createTokenizer('code'); // Math.ceil(chars / 3)
|
|
386
|
+
|
|
387
|
+
// Use the counter
|
|
388
|
+
const count = tokenizer.count('Hello, world!'); // Returns: number
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### Helper Functions
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
import { countTokens, encodeText } from 'opencode-tps-meter/dist/tokenCounter.js';
|
|
395
|
+
|
|
396
|
+
// Direct token counting with default heuristic
|
|
397
|
+
const tokens = countTokens('Hello, world!');
|
|
398
|
+
|
|
399
|
+
// Encode placeholder (returns empty array)
|
|
400
|
+
const encoded = encodeText('text'); // Returns: []
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Individual Counter Creators
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
import {
|
|
407
|
+
createHeuristicCounter, // char/4 based
|
|
408
|
+
createWordHeuristicCounter, // word/0.75 based
|
|
409
|
+
createCodeHeuristicCounter // char/3 based
|
|
410
|
+
} from 'opencode-tps-meter/dist/tokenCounter.js';
|
|
411
|
+
|
|
412
|
+
const counter = createHeuristicCounter();
|
|
413
|
+
const count = counter.count('Hello, world!');
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
## Token Counting Heuristics
|
|
419
|
+
|
|
420
|
+
| Method | Algorithm | Best For | Accuracy |
|
|
421
|
+
|--------|-----------|----------|----------|
|
|
422
|
+
| `chars_div_4` | `Math.ceil(chars / 4)` | General text | ~75% |
|
|
423
|
+
| `words_div_0_75` | `Math.ceil(words / 0.75)` | English prose | ~80% |
|
|
424
|
+
| `chars_div_3` | `Math.ceil(chars / 3)` | Code | ~70% |
|
|
425
|
+
|
|
426
|
+
**Note:** This plugin uses fast heuristic token counting. It does not include gpt-tokenizer or similar heavy tokenization libraries to keep the bundle size small and avoid bundling issues.
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## How It Works
|
|
431
|
+
|
|
432
|
+
### Event Handling
|
|
433
|
+
|
|
434
|
+
The plugin subscribes to three OpenCode event types:
|
|
435
|
+
|
|
436
|
+
1. **`message.part.updated`** — Processes streaming token chunks
|
|
437
|
+
- **Role Filtering**: Only tracks parts belonging to messages with `role: "assistant"`
|
|
438
|
+
- **User prompts excluded**: Prevents TPS spikes from user input (which would appear as thousands of TPS since prompts arrive instantly)
|
|
439
|
+
- **Counted parts**: Only `text` and `reasoning` are counted toward TPS
|
|
440
|
+
- **Ignored parts**: `tool`, `patch`, `snapshot`, `file`, `subtask`, `agent`, `retry`, `compaction`
|
|
441
|
+
- **Minimum elapsed time**: TPS display begins only after 250ms of assistant output
|
|
442
|
+
- Calculates delta tokens between consecutive updates
|
|
443
|
+
- Updates tracker and throttled UI display
|
|
444
|
+
|
|
445
|
+
2. **`message.updated`** — Handles message status changes
|
|
446
|
+
- Records role information (`user`, `assistant`, `system`) for each message ID
|
|
447
|
+
- Used to filter parts in `message.part.updated` events
|
|
448
|
+
- Processes official token counts from API responses when available
|
|
449
|
+
- Displays final stats when message completes
|
|
450
|
+
|
|
451
|
+
3. **`session.idle`** — Cleanup trigger
|
|
452
|
+
- Removes tracker for the specific session
|
|
453
|
+
- Clears all session-specific caches (role cache, token cache, part text cache)
|
|
454
|
+
- Cleans up UI when no active sessions remain
|
|
455
|
+
|
|
456
|
+
### Part Types Counted
|
|
457
|
+
|
|
458
|
+
Only these message part types contribute to TPS:
|
|
459
|
+
- `text` — Assistant output text
|
|
460
|
+
- `reasoning` — Assistant reasoning stream
|
|
461
|
+
|
|
462
|
+
All other part types are ignored to avoid counting tool output, snapshots, patches, or file contents as model tokens.
|
|
463
|
+
|
|
464
|
+
### Ring Buffer
|
|
465
|
+
|
|
466
|
+
The tracker uses a fixed-size ring buffer (max 100 entries) with automatic pruning:
|
|
467
|
+
- Removes entries older than the rolling window
|
|
468
|
+
- Enforces maximum size with FIFO eviction
|
|
469
|
+
- Efficient for high-frequency token streams
|
|
470
|
+
|
|
471
|
+
---
|
|
472
|
+
|
|
473
|
+
## Build System
|
|
474
|
+
|
|
475
|
+
This project uses **Bun** for building dual-format outputs:
|
|
476
|
+
|
|
477
|
+
```bash
|
|
478
|
+
# Install dependencies
|
|
479
|
+
bun install
|
|
480
|
+
|
|
481
|
+
# Run tests
|
|
482
|
+
bun test
|
|
483
|
+
|
|
484
|
+
# Build ESM + CJS outputs
|
|
485
|
+
bun run build
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### Build Outputs
|
|
489
|
+
|
|
490
|
+
- `dist/index.mjs` — ESM build
|
|
491
|
+
- `dist/index.js` — CommonJS build (with OpenCode compatibility fix)
|
|
492
|
+
- `dist/index.d.ts` — TypeScript declarations
|
|
493
|
+
|
|
494
|
+
**Note:** The CJS build requires a manual export fix for OpenCode compatibility:
|
|
495
|
+
```typescript
|
|
496
|
+
// Replaces: module.exports = __toCommonJS(exports_src);
|
|
497
|
+
// With: module.exports = exports_src.default();
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
## Troubleshooting
|
|
503
|
+
|
|
504
|
+
### Plugin Not Displaying
|
|
505
|
+
|
|
506
|
+
- ✅ Verify `TPS_METER_ENABLED` is not set to `false`
|
|
507
|
+
- ✅ Check that OpenCode client has `tui.showToast`, `tui.publish`, or `toast.info` methods
|
|
508
|
+
- ✅ Ensure you're viewing **assistant role** messages (user/system are filtered)
|
|
509
|
+
- ✅ Check that `minVisibleTps` threshold is not set too high
|
|
510
|
+
|
|
511
|
+
### High TPS on First Message (Fixed)
|
|
512
|
+
|
|
513
|
+
If you see extremely high TPS values (e.g., `TPS: 13590.0`) on the first message of a session, this is now fixed. The plugin now:
|
|
514
|
+
- Filters out **user prompts** (which would count as instant tokens)
|
|
515
|
+
- Only tracks **assistant responses** (actual AI output)
|
|
516
|
+
- Excludes **file parts** from token counting
|
|
517
|
+
- Applies a **250ms minimum elapsed time** before showing TPS
|
|
518
|
+
|
|
519
|
+
If you still see issues, ensure you're on the latest version with role filtering enabled.
|
|
520
|
+
|
|
521
|
+
### Incorrect Token Counts
|
|
522
|
+
|
|
523
|
+
- For general text: Use `fallbackTokenHeuristic: 'chars_div_4'` (default)
|
|
524
|
+
- For prose: Use `fallbackTokenHeuristic: 'words_div_0_75'`
|
|
525
|
+
- For code: Use `fallbackTokenHeuristic: 'chars_div_3'`
|
|
526
|
+
- Remember: Tool outputs, patches, snapshots, and file parts are always excluded from counting
|
|
527
|
+
- This plugin uses fast heuristics, not exact tokenizers like gpt-tokenizer
|
|
528
|
+
|
|
529
|
+
### High CPU Usage
|
|
530
|
+
|
|
531
|
+
- Increase `updateIntervalMs` (try 100ms or 200ms)
|
|
532
|
+
- Increase `rollingWindowMs` if using short windows
|
|
533
|
+
- Disable `showElapsed` if not needed
|
|
534
|
+
- Check buffer size with `tracker.getBufferSize()`
|
|
535
|
+
|
|
536
|
+
### Import Errors
|
|
537
|
+
|
|
538
|
+
**Main Plugin (ESM & CommonJS):**
|
|
539
|
+
```typescript
|
|
540
|
+
import TpsMeterPlugin from 'opencode-tps-meter';
|
|
541
|
+
// or
|
|
542
|
+
const TpsMeterPlugin = require('opencode-tps-meter');
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
**Source/Dist files (for programmatic API):**
|
|
546
|
+
```typescript
|
|
547
|
+
// From built dist files
|
|
548
|
+
import { createTracker } from 'opencode-tps-meter/dist/tracker.js';
|
|
549
|
+
import { createUIManager } from 'opencode-tps-meter/dist/ui.js';
|
|
550
|
+
import { createTokenizer } from 'opencode-tps-meter/dist/tokenCounter.js';
|
|
551
|
+
|
|
552
|
+
// Or from source (if your bundler supports it)
|
|
553
|
+
import { createTracker } from 'opencode-tps-meter/src/tracker.js';
|
|
554
|
+
import { createUIManager } from 'opencode-tps-meter/src/ui.js';
|
|
555
|
+
import { createTokenizer } from 'opencode-tps-meter/src/tokenCounter.js';
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
Both formats include full TypeScript declarations.
|
|
559
|
+
|
|
560
|
+
---
|
|
561
|
+
|
|
562
|
+
## Exported Types
|
|
563
|
+
|
|
564
|
+
```typescript
|
|
565
|
+
export type {
|
|
566
|
+
BufferEntry, // Ring buffer entry structure
|
|
567
|
+
TPSTrackerOptions, // Tracker configuration
|
|
568
|
+
TPSTracker, // Tracker interface
|
|
569
|
+
UIManager, // UI manager interface
|
|
570
|
+
TokenCounter, // Token counter interface
|
|
571
|
+
Config, // Plugin configuration
|
|
572
|
+
OpenCodeClient, // OpenCode client interface
|
|
573
|
+
UIManagerConfig, // UI configuration
|
|
574
|
+
DisplayState, // Display state structure
|
|
575
|
+
PluginContext, // Plugin context
|
|
576
|
+
Logger, // Logger interface
|
|
577
|
+
MessageEvent, // Event structure
|
|
578
|
+
PluginHandlers, // Handler return type
|
|
579
|
+
} from 'opencode-tps-meter';
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
## License
|
|
585
|
+
|
|
586
|
+
MIT
|
|
587
|
+
|
|
588
|
+
---
|
|
589
|
+
|
|
590
|
+
<div align="center">
|
|
591
|
+
|
|
592
|
+
Made for the OpenCode community
|
|
593
|
+
|
|
594
|
+
</div>
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration management for OpenCode TPS Meter Plugin
|
|
3
|
+
*
|
|
4
|
+
* Handles loading configuration from multiple sources in priority order:
|
|
5
|
+
* 1. Project-level config (.opencode/tps-meter.json)
|
|
6
|
+
* 2. Global config (~/.config/opencode/tps-meter.json)
|
|
7
|
+
* 3. Environment variables (TPS_METER_*)
|
|
8
|
+
*
|
|
9
|
+
* @module config
|
|
10
|
+
*/
|
|
11
|
+
import type { Config } from "./types.js";
|
|
12
|
+
/**
|
|
13
|
+
* Default configuration values
|
|
14
|
+
* Used when no config file is found or values are missing
|
|
15
|
+
*
|
|
16
|
+
* @constant {Config}
|
|
17
|
+
*/
|
|
18
|
+
export declare const defaultConfig: Config;
|
|
19
|
+
/**
|
|
20
|
+
* Loads configuration from multiple sources in priority order:
|
|
21
|
+
* 1. .opencode/tps-meter.json (project-level)
|
|
22
|
+
* 2. ~/.config/opencode/tps-meter.json (global)
|
|
23
|
+
* 3. Environment variables (TPS_METER_*)
|
|
24
|
+
*
|
|
25
|
+
* Later sources override earlier ones.
|
|
26
|
+
*
|
|
27
|
+
* @returns {Config} - Resolved configuration with all defaults applied
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* const config = loadConfigSync();
|
|
31
|
+
* if (config.enabled) {
|
|
32
|
+
* // Initialize plugin
|
|
33
|
+
* }
|
|
34
|
+
*/
|
|
35
|
+
export declare function loadConfigSync(): Config;
|
|
36
|
+
/**
|
|
37
|
+
* Exports default config for external access
|
|
38
|
+
* @deprecated Use loadConfigSync() to get resolved configuration
|
|
39
|
+
*/
|
|
40
|
+
export { defaultConfig as config };
|
|
41
|
+
/**
|
|
42
|
+
* Backwards-compatible alias for loadConfigSync
|
|
43
|
+
* @deprecated Use loadConfigSync() instead
|
|
44
|
+
*/
|
|
45
|
+
export { loadConfigSync as loadConfig };
|
|
46
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAQzC;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,MAc3B,CAAC;AA6OF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAiCvC;AAED;;;GAGG;AACH,OAAO,EAAE,aAAa,IAAI,MAAM,EAAE,CAAC;AAEnC;;;GAGG;AACH,OAAO,EAAE,cAAc,IAAI,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants for OpenCode TPS Meter Plugin
|
|
3
|
+
*
|
|
4
|
+
* Centralized configuration constants to avoid magic numbers
|
|
5
|
+
* scattered throughout the codebase.
|
|
6
|
+
*
|
|
7
|
+
* @module constants
|
|
8
|
+
*/
|
|
9
|
+
/** Minimum elapsed time (ms) before displaying TPS to avoid initial spikes */
|
|
10
|
+
export declare const MIN_TPS_ELAPSED_MS = 250;
|
|
11
|
+
/** Default rolling window duration for TPS calculation (ms) */
|
|
12
|
+
export declare const DEFAULT_ROLLING_WINDOW_MS = 1000;
|
|
13
|
+
/** Maximum number of entries in the ring buffer */
|
|
14
|
+
export declare const MAX_BUFFER_SIZE = 100;
|
|
15
|
+
/** Minimum window duration for TPS calculation (seconds) to avoid division by near-zero */
|
|
16
|
+
export declare const MIN_WINDOW_DURATION_SECONDS = 0.1;
|
|
17
|
+
/** Default UI update interval in milliseconds */
|
|
18
|
+
export declare const DEFAULT_UPDATE_INTERVAL_MS = 50;
|
|
19
|
+
/** Minimum interval between toast updates (ms) - prevents UI flooding */
|
|
20
|
+
export declare const MIN_TOAST_INTERVAL_MS = 150;
|
|
21
|
+
/** Default toast display duration in milliseconds */
|
|
22
|
+
export declare const DEFAULT_TOAST_DURATION_MS = 20000;
|
|
23
|
+
/** Duration for final stats toast in milliseconds */
|
|
24
|
+
export declare const FINAL_STATS_DURATION_MS = 2000;
|
|
25
|
+
/** Maximum age of message entries before cleanup (5 minutes in ms) */
|
|
26
|
+
export declare const MAX_MESSAGE_AGE_MS: number;
|
|
27
|
+
/** Interval between stale message cleanup runs (30 seconds in ms) */
|
|
28
|
+
export declare const CLEANUP_INTERVAL_MS = 30000;
|
|
29
|
+
/** Character divisor for general heuristic token counting (chars / 4) */
|
|
30
|
+
export declare const CHARS_DIV_4 = 4;
|
|
31
|
+
/** Character divisor for code-optimized token counting (chars / 3) */
|
|
32
|
+
export declare const CHARS_DIV_3 = 3;
|
|
33
|
+
/** Word divisor for prose-optimized token counting (words / 0.75) */
|
|
34
|
+
export declare const WORDS_DIV_0_75 = 0.75;
|
|
35
|
+
/** Default TPS threshold for "slow" (red) indicator */
|
|
36
|
+
export declare const DEFAULT_SLOW_TPS_THRESHOLD = 10;
|
|
37
|
+
/** Default TPS threshold for "fast" (green) indicator */
|
|
38
|
+
export declare const DEFAULT_FAST_TPS_THRESHOLD = 50;
|
|
39
|
+
/** Set of finish reasons that invalidate TPS statistics */
|
|
40
|
+
export declare const INVALID_FINISH_REASONS: Set<string>;
|
|
41
|
+
/** Set of part types that contribute to token counting */
|
|
42
|
+
export declare const COUNTABLE_PART_TYPES: Set<string>;
|
|
43
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC,+DAA+D;AAC/D,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAE9C,mDAAmD;AACnD,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,2FAA2F;AAC3F,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAM/C,iDAAiD;AACjD,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAE7C,yEAAyE;AACzE,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,qDAAqD;AACrD,eAAO,MAAM,yBAAyB,QAAQ,CAAC;AAE/C,qDAAqD;AACrD,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAM5C,sEAAsE;AACtE,eAAO,MAAM,kBAAkB,QAAgB,CAAC;AAEhD,qEAAqE;AACrE,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAMzC,yEAAyE;AACzE,eAAO,MAAM,WAAW,IAAI,CAAC;AAE7B,sEAAsE;AACtE,eAAO,MAAM,WAAW,IAAI,CAAC;AAE7B,qEAAqE;AACrE,eAAO,MAAM,cAAc,OAAO,CAAC;AAMnC,uDAAuD;AACvD,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAE7C,yDAAyD;AACzD,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAM7C,2DAA2D;AAC3D,eAAO,MAAM,sBAAsB,aAAqC,CAAC;AAEzE,0DAA0D;AAC1D,eAAO,MAAM,oBAAoB,aAAiC,CAAC"}
|