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 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** showing:
8
- - Session input/output tokens & estimated cost
9
- - Live TPS (tokens per second) during streaming
10
- - Session runtime
11
- - Current model, thinking level, fast mode & git branch
12
- - Git diff stats (added/removed lines)
13
- - Context usage (current / max)
14
- - **Thinking level colors match pi's input field** — off/low/medium/high use the same theme colors as the editor border
15
- - **Rainbow mode** — `xhigh` and `max` thinking levels render the model indicator in cycling rainbow colors
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
- ## Preview
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
- [![Animated preview of pi-observability](./demo-preview.gif)](./output.mp4)
25
+ ## Preview
30
26
 
31
- [Open the full screed recording (MP4)](./output.mp4)
27
+ ![pi-observability demo](./demo-preview.gif)
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 ▸ ⚡45.2 ▸ $0.0042
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 ▸ ⚡45.2 ▸ $0.0042
40
+ gpt-5.5:xhigh ▸ ⏱ 12:34 ▸ 📁 my-app ▸ ↑1.2k ↓3.4k ▸ $0.0042
45
41
  ```
46
42
 
47
- ### Git diff in the status bar
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
- ![Git diff in the footer status bar](./diff.png)
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 "@mariozechner/pi-coding-agent";
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 "@mariozechner/pi-tui";
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 "@mariozechner/pi-coding-agent";
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 "@mariozechner/pi-ai";
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 "@mariozechner/pi-coding-agent";
29
- import { Key, matchesKey, SettingsList, truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
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.api !== "openai-codex-responses") return false;
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)?.toLowerCase() ?? null;
349
- state.fastModeEnabled = state.serviceTier === "fast";
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.0",
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
- "@mariozechner/pi-ai": "latest",
41
- "@mariozechner/pi-coding-agent": "latest",
42
- "@mariozechner/pi-tui": "latest",
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
- "@mariozechner/pi-ai": "*",
49
- "@mariozechner/pi-coding-agent": "*",
50
- "@mariozechner/pi-tui": "*"
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