pi-observability 1.3.0 → 1.3.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 +46 -20
- package/demo-preview.gif +0 -0
- package/extensions/lib/footer-engine/format.ts +1 -1
- package/extensions/lib/footer-engine/layout.ts +1 -1
- package/extensions/lib/footer-engine/segments.ts +4 -3
- package/extensions/lib/footer-engine/types.ts +4 -1
- package/extensions/observability.ts +26 -12
- package/package.json +7 -7
- package/diff.png +0 -0
- package/output.mp4 +0 -0
package/README.md
CHANGED
|
@@ -4,15 +4,15 @@ A [pi](https://github.com/mariozechner/pi) extension that replaces the default f
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **Live footer bar**
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
7
|
+
- **Live footer bar** — Fully customizable status bar with configurable segments, layout presets, and context-zone thresholds:
|
|
8
|
+
- **Model & thinking level** — Colors match pi's input field (off/low/medium/high). `xhigh`/`max` renders in rainbow
|
|
9
|
+
- **Session runtime**
|
|
10
|
+
- **Working directory** — Toggle between folder name or full path
|
|
11
|
+
- **Git branch & diff stats** — Added/removed lines
|
|
12
|
+
- **Context usage** — Progress bar + percentage + token count, with color-coded zones
|
|
13
|
+
- **Session tokens** — Input/output totals
|
|
14
|
+
- **Live TPS** — During streaming (chunk-based estimate)
|
|
15
|
+
- **Estimated cost**
|
|
16
16
|
|
|
17
17
|
- **`/obs` command** — Full-screen TUI dashboard with per-turn breakdowns and last 10 session history. Renders through pi's native TUI (no console spam), with theme-aware borders and dynamic terminal width.
|
|
18
18
|
|
|
@@ -20,33 +20,58 @@ A [pi](https://github.com/mariozechner/pi) extension that replaces the default f
|
|
|
20
20
|
|
|
21
21
|
- **`/obs-toggle` command** — Toggle the live footer on/off
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
### Screed recording
|
|
26
|
-
|
|
27
|
-
> GitHub does not render inline MP4 players in `README.md`, so here's a short animated preview. Click it to open the full recording.
|
|
23
|
+
- **`/obs-settings` command** — Interactive TUI for customizing the footer: choose from 4 layout presets or toggle individual segments and set context-usage warning thresholds
|
|
28
24
|
|
|
29
|
-
|
|
25
|
+
## Preview
|
|
30
26
|
|
|
31
|
-
[
|
|
27
|
+

|
|
32
28
|
|
|
33
29
|
### Footer
|
|
34
30
|
|
|
35
31
|
Compact single-line layout that falls back to two lines when the terminal is narrow:
|
|
36
32
|
|
|
37
33
|
```
|
|
38
|
-
gpt-5.5:high ▸ ⏱ 12:34 ▸ 📁 my-app ▸ main +42 -7 ▸ ctx 4.2k/200k ▸ ↑1.2k ↓3.4k ▸
|
|
34
|
+
gpt-5.5:high ▸ ⏱ 12:34 ▸ 📁 my-app ▸ main +42 -7 ▸ ctx [████░░░░░░] 42% 4.2k/200k ▸ ↑1.2k ↓3.4k ▸ $0.0042
|
|
39
35
|
```
|
|
40
36
|
|
|
41
37
|
With `xhigh` or `max` thinking, the model name renders in rainbow:
|
|
42
38
|
|
|
43
39
|
```
|
|
44
|
-
gpt-5.5:xhigh ▸ ⏱ 12:34 ▸ 📁 my-app ▸ ↑1.2k ↓3.4k ▸
|
|
40
|
+
gpt-5.5:xhigh ▸ ⏱ 12:34 ▸ 📁 my-app ▸ ↑1.2k ↓3.4k ▸ $0.0042
|
|
45
41
|
```
|
|
46
42
|
|
|
47
|
-
|
|
43
|
+
#### Settings
|
|
44
|
+
|
|
45
|
+
Run `/obs-settings` to open the interactive settings panel:
|
|
46
|
+
|
|
47
|
+
| Preset | Description |
|
|
48
|
+
|--------|-------------|
|
|
49
|
+
| `minimal` | Model, context usage (bar + numbers), cost only |
|
|
50
|
+
| `standard` | Everything except TPS (default) |
|
|
51
|
+
| `verbose` | All segments on |
|
|
52
|
+
| `performance` | Model, context %, TPS, cost |
|
|
53
|
+
|
|
54
|
+
Individual segments you can toggle:
|
|
55
|
+
|
|
56
|
+
- **Model & Thinking** — Model name + thinking level
|
|
57
|
+
- **Runtime** — Session timer
|
|
58
|
+
- **Working Directory** — Current folder or full path (`/obs-toggle-path`)
|
|
59
|
+
- **Git Branch & Diff** — Branch name + added/removed line counts
|
|
60
|
+
- **Context Usage** — Master toggle with 3 sub-options:
|
|
61
|
+
- Progress bar (`[████░░░░░░]`)
|
|
62
|
+
- Percentage
|
|
63
|
+
- Token count (`used/total`)
|
|
64
|
+
- **Session Tokens** — Total input/output
|
|
65
|
+
- **TPS** — Live during streaming, last-turn when idle
|
|
66
|
+
- **Cost** — Estimated session cost
|
|
67
|
+
|
|
68
|
+
Context-usage color zones (configurable):
|
|
48
69
|
|
|
49
|
-
|
|
70
|
+
| Zone | Default | Color |
|
|
71
|
+
|------|---------|-------|
|
|
72
|
+
| Normal | ≤ 70% | Green |
|
|
73
|
+
| Expert | 71–85% | Yellow |
|
|
74
|
+
| Warning | > 85% | Red |
|
|
50
75
|
|
|
51
76
|
### Dashboard (`/obs`)
|
|
52
77
|
|
|
@@ -104,6 +129,7 @@ cp -r extensions/* ~/.pi/agent/extensions/
|
|
|
104
129
|
| `/obs` | Open full observability dashboard in TUI overlay |
|
|
105
130
|
| `/obs-toggle` | Toggle the observability footer on/off |
|
|
106
131
|
| `/obs-toggle-path` | Toggle between folder name and full path in footer |
|
|
132
|
+
| `/obs-settings` | Open interactive footer settings (presets, segments, context zones) |
|
|
107
133
|
|
|
108
134
|
## Migration from TPS
|
|
109
135
|
|
package/demo-preview.gif
CHANGED
|
Binary file
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
|
-
import type { ThemeColor } from "@
|
|
2
|
+
import type { ThemeColor } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
|
|
4
4
|
export function fmtDuration(ms: number): string {
|
|
5
5
|
if (!Number.isFinite(ms) || ms < 0) ms = 0;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { visibleWidth, truncateToWidth } from "@
|
|
1
|
+
import { visibleWidth, truncateToWidth } from "@earendil-works/pi-tui";
|
|
2
2
|
import type { LayoutAssembler } from "./types.js";
|
|
3
3
|
|
|
4
4
|
export const defaultAssembler: LayoutAssembler = (segments, width, theme) => {
|
|
@@ -11,12 +11,13 @@ import {
|
|
|
11
11
|
|
|
12
12
|
export const builtinRenderers: Record<string, SegmentRenderer> = {
|
|
13
13
|
modelThink(input) {
|
|
14
|
-
const { model, thinkingLevel, theme } = input;
|
|
14
|
+
const { model, thinkingLevel, fastModeEnabled, serviceTier, theme } = input;
|
|
15
15
|
const text = `${model}:${thinkingLevel}`;
|
|
16
|
+
const tier = fastModeEnabled ? theme.fg("accent", ` ⚡${serviceTier ?? "fast"}`) : "";
|
|
16
17
|
if (thinkingLevel === "xhigh" || thinkingLevel === "max") {
|
|
17
|
-
return rainbowText(text);
|
|
18
|
+
return rainbowText(text) + tier;
|
|
18
19
|
}
|
|
19
|
-
return theme.fg(thinkingColor(thinkingLevel), text);
|
|
20
|
+
return theme.fg(thinkingColor(thinkingLevel), text) + tier;
|
|
20
21
|
},
|
|
21
22
|
|
|
22
23
|
runtime(input) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ContextUsage, Theme as PiTheme } from "@
|
|
1
|
+
import type { ContextUsage, Theme as PiTheme } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
|
|
3
3
|
export type SegmentKey =
|
|
4
4
|
| "modelThink"
|
|
@@ -29,6 +29,9 @@ export interface FooterInput {
|
|
|
29
29
|
totalInputTokens: number;
|
|
30
30
|
totalOutputTokens: number;
|
|
31
31
|
totalCost: number;
|
|
32
|
+
fastModeSupported: boolean;
|
|
33
|
+
fastModeEnabled: boolean;
|
|
34
|
+
serviceTier: string | null;
|
|
32
35
|
contextUsage: ContextUsage | null;
|
|
33
36
|
cwd: string;
|
|
34
37
|
showFullPath: boolean;
|
|
@@ -20,13 +20,19 @@
|
|
|
20
20
|
|
|
21
21
|
import { homedir } from "node:os";
|
|
22
22
|
import { join } from "node:path";
|
|
23
|
-
import type { AssistantMessage } from "@
|
|
23
|
+
import type { AssistantMessage } from "@earendil-works/pi-ai";
|
|
24
24
|
import type {
|
|
25
25
|
ExtensionAPI,
|
|
26
26
|
ExtensionContext,
|
|
27
27
|
Theme as PiTheme,
|
|
28
|
-
} from "@
|
|
29
|
-
import {
|
|
28
|
+
} from "@earendil-works/pi-coding-agent";
|
|
29
|
+
import {
|
|
30
|
+
Key,
|
|
31
|
+
matchesKey,
|
|
32
|
+
SettingsList,
|
|
33
|
+
truncateToWidth,
|
|
34
|
+
visibleWidth,
|
|
35
|
+
} from "@earendil-works/pi-tui";
|
|
30
36
|
|
|
31
37
|
import {
|
|
32
38
|
loadSettings,
|
|
@@ -127,18 +133,20 @@ function getStringProp(value: unknown, key: string): string | undefined {
|
|
|
127
133
|
|
|
128
134
|
function getServiceTierFromPayload(payload: unknown): string | null {
|
|
129
135
|
const tier = getStringProp(payload, "service_tier") ?? getStringProp(payload, "serviceTier");
|
|
130
|
-
return tier?.trim() || null;
|
|
136
|
+
return tier?.trim().toLowerCase() || null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function isFastServiceTier(serviceTier: string | null): boolean {
|
|
140
|
+
// OpenAI's actual fast/priority tier is `priority`. Older/local shims may
|
|
141
|
+
// still emit `fast`, so keep accepting it for backwards-compatible display.
|
|
142
|
+
return serviceTier === "priority" || serviceTier === "fast";
|
|
131
143
|
}
|
|
132
144
|
|
|
133
145
|
function supportsFastMode(ctx: ExtensionContext): boolean {
|
|
134
146
|
const model = ctx.model;
|
|
135
147
|
if (!model) return false;
|
|
136
|
-
if (model.
|
|
137
|
-
return
|
|
138
|
-
model.provider === "openai-codex" ||
|
|
139
|
-
model.provider === "openai" ||
|
|
140
|
-
model.id.toLowerCase().includes("gpt-5.5")
|
|
141
|
-
);
|
|
148
|
+
if (model.provider !== "openai" && model.provider !== "openai-codex") return false;
|
|
149
|
+
return model.api === "openai-responses" || model.api === "openai-codex-responses";
|
|
142
150
|
}
|
|
143
151
|
|
|
144
152
|
/* ───── Dashboard formatting ───── */
|
|
@@ -168,6 +176,9 @@ function buildDashboard(
|
|
|
168
176
|
branch
|
|
169
177
|
? `Branch: ${branch} Model: ${ctx.model?.id ?? "none"}`
|
|
170
178
|
: `Model: ${ctx.model?.id ?? "none"}`,
|
|
179
|
+
state.serviceTier
|
|
180
|
+
? `Service tier: ${state.serviceTier}${state.fastModeEnabled ? " (fast)" : ""}`
|
|
181
|
+
: `Fast mode: ${state.fastModeSupported ? "available" : "not available"}`,
|
|
171
182
|
`Tokens: ↑${fmtTokens(totalIn)} ↓${fmtTokens(totalOut)}`,
|
|
172
183
|
`Cost: $${totalCost.toFixed(6)}`,
|
|
173
184
|
];
|
|
@@ -345,8 +356,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
345
356
|
});
|
|
346
357
|
|
|
347
358
|
pi.on("before_provider_request", async (event, ctx) => {
|
|
348
|
-
state.serviceTier = getServiceTierFromPayload(event.payload)
|
|
349
|
-
state.fastModeEnabled = state.serviceTier
|
|
359
|
+
state.serviceTier = getServiceTierFromPayload(event.payload);
|
|
360
|
+
state.fastModeEnabled = isFastServiceTier(state.serviceTier);
|
|
350
361
|
state.fastModeSupported = supportsFastMode(ctx) || state.fastModeEnabled;
|
|
351
362
|
});
|
|
352
363
|
|
|
@@ -539,6 +550,9 @@ export default function (pi: ExtensionAPI) {
|
|
|
539
550
|
totalInputTokens: totalIn,
|
|
540
551
|
totalOutputTokens: totalOut,
|
|
541
552
|
totalCost,
|
|
553
|
+
fastModeSupported: state.fastModeSupported,
|
|
554
|
+
fastModeEnabled: state.fastModeEnabled,
|
|
555
|
+
serviceTier: state.serviceTier,
|
|
542
556
|
contextUsage: ctx.getContextUsage() ?? null,
|
|
543
557
|
cwd: ctx.cwd,
|
|
544
558
|
showFullPath: state.showFullPath,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-observability",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Live observability dashboard for pi coding agent sessions — tokens, cost, TPS, runtime, git stats, and context usage",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -37,17 +37,17 @@
|
|
|
37
37
|
"publish:pkg": "npm publish"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@
|
|
41
|
-
"@
|
|
42
|
-
"@
|
|
40
|
+
"@earendil-works/pi-ai": "latest",
|
|
41
|
+
"@earendil-works/pi-coding-agent": "latest",
|
|
42
|
+
"@earendil-works/pi-tui": "latest",
|
|
43
43
|
"oxfmt": "^0.47.0",
|
|
44
44
|
"oxlint": "^1.62.0",
|
|
45
45
|
"typescript": "^5.4.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
|
-
"@
|
|
49
|
-
"@
|
|
50
|
-
"@
|
|
48
|
+
"@earendil-works/pi-ai": "*",
|
|
49
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
50
|
+
"@earendil-works/pi-tui": "*"
|
|
51
51
|
},
|
|
52
52
|
"pi": {
|
|
53
53
|
"extensions": [
|
package/diff.png
DELETED
|
Binary file
|
package/output.mp4
DELETED
|
Binary file
|