useful-pi-extensions 1.1.1 → 1.1.2
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "useful-pi-extensions",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "A small collection of pi extensions, installed with one command — a labelled status line with context pressure, cache, cost, effort, TTFT and tokens/sec.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bun",
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
pair,
|
|
40
40
|
row,
|
|
41
41
|
shortenPath,
|
|
42
|
+
ttftMs,
|
|
42
43
|
USD,
|
|
43
44
|
type Currency,
|
|
44
45
|
} from './render.ts'
|
|
@@ -185,7 +186,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
185
186
|
let reading: { rate: number; exact: boolean; ttftMs: number | null } | null = null
|
|
186
187
|
|
|
187
188
|
let chars = 0
|
|
188
|
-
let
|
|
189
|
+
let requestAt: number | null = null
|
|
189
190
|
let firstTokenAt: number | null = null
|
|
190
191
|
let windowAt = 0
|
|
191
192
|
let windowTokens = 0
|
|
@@ -199,8 +200,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
199
200
|
renderedAt = 0
|
|
200
201
|
}
|
|
201
202
|
|
|
202
|
-
function publish(rate: number, exact: boolean,
|
|
203
|
-
reading = { rate, exact, ttftMs }
|
|
203
|
+
function publish(rate: number, exact: boolean, ttft: number | null): void {
|
|
204
|
+
reading = { rate, exact, ttftMs: ttft }
|
|
204
205
|
requestRender?.()
|
|
205
206
|
}
|
|
206
207
|
|
|
@@ -286,6 +287,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
286
287
|
pi.on('session_start', async (_event, ctx) => {
|
|
287
288
|
ratio = seedRatio(ctx)
|
|
288
289
|
reading = null
|
|
290
|
+
requestAt = null
|
|
289
291
|
resetStream()
|
|
290
292
|
currency = await loadCurrency((message) => ctx.ui.notify(message, 'warning'))
|
|
291
293
|
installFooter(ctx)
|
|
@@ -294,7 +296,17 @@ export default function (pi: ExtensionAPI) {
|
|
|
294
296
|
pi.on('message_start', async (event) => {
|
|
295
297
|
if (event.message.role !== 'assistant') return
|
|
296
298
|
resetStream()
|
|
297
|
-
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
// TTFT's request anchor, from the agent loop in pi's docs: turn_start opens the LLM call and
|
|
302
|
+
// before_provider_request is the last thing pi does before the wire. message_start is not that
|
|
303
|
+
// moment, and anchoring there made a first token that arrived early read as a clamped 0ms.
|
|
304
|
+
pi.on('turn_start', async () => {
|
|
305
|
+
requestAt = null
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
pi.on('before_provider_request', async () => {
|
|
309
|
+
requestAt = Date.now()
|
|
298
310
|
})
|
|
299
311
|
|
|
300
312
|
pi.on('message_update', async (event) => {
|
|
@@ -326,7 +338,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
326
338
|
const rate =
|
|
327
339
|
windowMs > 0 ? ((tokens - windowTokens) / windowMs) * 1000 : (tokens / decodeMs) * 1000
|
|
328
340
|
renderedAt = now
|
|
329
|
-
publish(rate, false, firstTokenAt
|
|
341
|
+
publish(rate, false, ttftMs(requestAt, firstTokenAt))
|
|
330
342
|
})
|
|
331
343
|
|
|
332
344
|
pi.on('message_end', async (event) => {
|
|
@@ -341,10 +353,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
341
353
|
}
|
|
342
354
|
|
|
343
355
|
const decodeMs = firstTokenAt !== null ? Date.now() - firstTokenAt : 0
|
|
344
|
-
const
|
|
356
|
+
const measured = ttftMs(requestAt, firstTokenAt)
|
|
345
357
|
const tokens = output > 0 ? output : totalChars * (ratio ?? FALLBACK_TOKENS_PER_CHAR)
|
|
346
|
-
if (
|
|
347
|
-
publish((tokens / decodeMs) * 1000, output > 0,
|
|
358
|
+
if (measured !== null && decodeMs >= MIN_SAMPLE_MS)
|
|
359
|
+
publish((tokens / decodeMs) * 1000, output > 0, measured)
|
|
348
360
|
resetStream()
|
|
349
361
|
})
|
|
350
362
|
}
|
|
@@ -66,6 +66,21 @@ export function formatLatency(ms: number): string {
|
|
|
66
66
|
return `${seconds < 10 ? Math.round(seconds * 10) / 10 : Math.round(seconds)}s`
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* TTFT from its two wall-clock anchors: the moment the request was dispatched, and the first
|
|
71
|
+
* streamed delta.
|
|
72
|
+
*
|
|
73
|
+
* The guard is the point. Both anchors come from extension events whose ordering around a stream is
|
|
74
|
+
* not guaranteed, and a first token that appears to precede its own request yields a negative that
|
|
75
|
+
* `formatLatency` would clamp to `0ms` — a confident fake where an honest absence belongs.
|
|
76
|
+
*
|
|
77
|
+
* @returns The milliseconds between the two, or null when they do not line up.
|
|
78
|
+
*/
|
|
79
|
+
export function ttftMs(requestAt: number | null, firstTokenAt: number | null): number | null {
|
|
80
|
+
if (requestAt === null || firstTokenAt === null) return null
|
|
81
|
+
return firstTokenAt > requestAt ? firstTokenAt - requestAt : null
|
|
82
|
+
}
|
|
83
|
+
|
|
69
84
|
/** Home-relative path, or the absolute path when it is outside the home directory. */
|
|
70
85
|
export function formatCwd(cwd: string): string {
|
|
71
86
|
const home = homedir()
|