@diegopetrucci/pi-extensions 0.1.69 → 0.1.71
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 +2 -2
- package/extensions/fast/README.md +21 -5
- package/extensions/fast/index.ts +40 -4
- package/extensions/fast/package.json +2 -2
- package/extensions/minimal-footer/README.md +10 -8
- package/extensions/minimal-footer/index.ts +2 -2
- package/extensions/minimal-footer/minimal-footer.example.json +2 -2
- package/extensions/minimal-footer/openai-usage.ts +52 -4
- package/extensions/minimal-footer/package.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,12 +13,12 @@ A collection of [pi](https://pi.dev) agent extensions I made. (Btw, [I am also b
|
|
|
13
13
|
|
|
14
14
|
### Providers
|
|
15
15
|
|
|
16
|
-
- [`fast`](./extensions/fast): Adds one `/fast` toggle that enables the provider-specific Fast mode for the currently selected supported OpenAI Codex or Anthropic Claude model.
|
|
16
|
+
- [`fast`](./extensions/fast): Adds one `/fast` toggle that enables the provider-specific Fast mode for the currently selected supported direct OpenAI API, OpenAI Codex, or Anthropic Claude model.
|
|
17
17
|
|
|
18
18
|
### UI
|
|
19
19
|
|
|
20
20
|
- [`git-footer`](./extensions/git-footer): Standalone extension that adds TLH-style git dirty counts, ahead/behind, and optional PR number to pi's built-in footer status area.
|
|
21
|
-
- [`minimal-footer`](./extensions/minimal-footer): Replaces pi's built-in footer with a minimal configurable two-line layout: branch plus cached git dirty/ahead/PR status and repo on the first line, context/model on the second, optional `DUMB ZONE`, optional `xp` marker, plus OpenAI Codex
|
|
21
|
+
- [`minimal-footer`](./extensions/minimal-footer): Replaces pi's built-in footer with a minimal configurable two-line layout: branch plus cached git dirty/ahead/PR status and repo on the first line, context/model on the second, optional `DUMB ZONE`, optional `xp` marker, plus OpenAI Codex usage windows labeled from their reported durations.
|
|
22
22
|
- [`quiet-tools`](./extensions/quiet-tools): Renders collapsed built-in tool rows as a one-line invocation plus an expand hint without changing model-visible tool results; toggle temporarily with `/quiet-tools`.
|
|
23
23
|
|
|
24
24
|
### / Slash commands
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
# fast
|
|
2
2
|
|
|
3
|
-
A pi extension that provides one `/fast` toggle for supported OpenAI Codex and Anthropic Claude models. It selects the provider-specific Fast-mode request shape from the currently selected model.
|
|
3
|
+
A pi extension that provides one `/fast` toggle for supported direct OpenAI API, OpenAI Codex, and Anthropic Claude models. It selects the provider-specific Fast-mode request shape from the currently selected model.
|
|
4
4
|
|
|
5
|
-
For eligible OpenAI
|
|
5
|
+
For eligible direct OpenAI API models it injects:
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"service_tier": "fast"
|
|
10
|
+
}
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
For eligible OpenAI Codex OAuth models it injects:
|
|
6
14
|
|
|
7
15
|
```json
|
|
8
16
|
{
|
|
@@ -26,7 +34,14 @@ anthropic-beta: fast-mode-2026-02-01
|
|
|
26
34
|
|
|
27
35
|
## Eligibility
|
|
28
36
|
|
|
29
|
-
OpenAI Fast mode requires all of the following:
|
|
37
|
+
Direct OpenAI API Fast mode requires all of the following:
|
|
38
|
+
|
|
39
|
+
- Provider `openai`.
|
|
40
|
+
- API `openai-responses` or `openai-completions`.
|
|
41
|
+
- Model `gpt-6-astra`, `gpt-6-sol`, or `gpt-6-luna`.
|
|
42
|
+
- No existing `service_tier` field in the request payload.
|
|
43
|
+
|
|
44
|
+
OpenAI Codex Fast mode requires all of the following:
|
|
30
45
|
|
|
31
46
|
- Provider `openai-codex`.
|
|
32
47
|
- API `openai-codex-responses`.
|
|
@@ -114,6 +129,7 @@ The collection package loads this unified extension instead of `openai-fast` and
|
|
|
114
129
|
## Notes
|
|
115
130
|
|
|
116
131
|
- Anthropic Fast mode has separate rate limits, costs more than standard speed, and does not share prompt-cache prefixes with standard-speed requests.
|
|
117
|
-
- OpenAI Fast mode
|
|
132
|
+
- Direct OpenAI Fast mode is limited to the confirmed, officially priced GPT-6 API models above; Fast pricing, availability, and rate limits remain provider- and account-dependent.
|
|
133
|
+
- OpenAI Codex Fast mode intentionally does not affect API-key models.
|
|
118
134
|
- Existing `speed` and `service_tier` fields are never overwritten.
|
|
119
|
-
- Cost accounting
|
|
135
|
+
- Pi's model catalog may not include a Fast-mode premium. Cost accounting depends on the provider reporting the effective tier in its streamed response, and this extension does not patch usage totals.
|
package/extensions/fast/index.ts
CHANGED
|
@@ -26,6 +26,10 @@ const OPENAI_SUPPORTED_MODELS = new Set([
|
|
|
26
26
|
"gpt-5.6-terra",
|
|
27
27
|
"gpt-5.6-luna",
|
|
28
28
|
]);
|
|
29
|
+
const OPENAI_API_PROVIDER_ID = "openai";
|
|
30
|
+
const OPENAI_API_IDS = new Set(["openai-responses", "openai-completions"]);
|
|
31
|
+
const OPENAI_API_FAST_SERVICE_TIER = "fast";
|
|
32
|
+
const OPENAI_API_SUPPORTED_MODELS = new Set(["gpt-6-astra", "gpt-6-sol", "gpt-6-luna"]);
|
|
29
33
|
|
|
30
34
|
const DEFAULT_CONFIG: FastConfig = {
|
|
31
35
|
enabled: false,
|
|
@@ -69,6 +73,7 @@ type Eligibility = {
|
|
|
69
73
|
eligible: boolean;
|
|
70
74
|
modelKey: string;
|
|
71
75
|
provider?: FastProvider;
|
|
76
|
+
serviceTier?: string;
|
|
72
77
|
reason?: string;
|
|
73
78
|
};
|
|
74
79
|
|
|
@@ -190,7 +195,37 @@ function getEligibility(ctx: ExtensionContext): Eligibility {
|
|
|
190
195
|
};
|
|
191
196
|
}
|
|
192
197
|
|
|
193
|
-
return {
|
|
198
|
+
return {
|
|
199
|
+
eligible: true,
|
|
200
|
+
modelKey: key,
|
|
201
|
+
provider: "openai",
|
|
202
|
+
serviceTier: OPENAI_FAST_SERVICE_TIER,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (model.provider === OPENAI_API_PROVIDER_ID) {
|
|
207
|
+
if (!OPENAI_API_IDS.has(model.api)) {
|
|
208
|
+
return {
|
|
209
|
+
eligible: false,
|
|
210
|
+
modelKey: key,
|
|
211
|
+
reason: `current API is ${model.api}, not openai-responses or openai-completions`,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (!OPENAI_API_SUPPORTED_MODELS.has(model.id)) {
|
|
216
|
+
return {
|
|
217
|
+
eligible: false,
|
|
218
|
+
modelKey: key,
|
|
219
|
+
reason: "Fast mode is only enabled for GPT-6 Astra, GPT-6 Sol, and GPT-6 Luna on direct OpenAI APIs",
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
eligible: true,
|
|
225
|
+
modelKey: key,
|
|
226
|
+
provider: "openai",
|
|
227
|
+
serviceTier: OPENAI_API_FAST_SERVICE_TIER,
|
|
228
|
+
};
|
|
194
229
|
}
|
|
195
230
|
|
|
196
231
|
return {
|
|
@@ -226,7 +261,7 @@ function getStatusMessage(ctx: ExtensionContext, state: SessionState): string {
|
|
|
226
261
|
const wireSetting =
|
|
227
262
|
eligibility.provider === "anthropic"
|
|
228
263
|
? `speed=${ANTHROPIC_FAST_SPEED}`
|
|
229
|
-
: `service_tier=${
|
|
264
|
+
: `service_tier=${eligibility.serviceTier}`;
|
|
230
265
|
return `Fast mode is ${describeMode(state)} and active for ${eligibility.modelKey}; requests will use ${wireSetting}.${injected}`;
|
|
231
266
|
}
|
|
232
267
|
|
|
@@ -317,9 +352,10 @@ function injectFastPayload(
|
|
|
317
352
|
}
|
|
318
353
|
|
|
319
354
|
if ("service_tier" in payload) return undefined;
|
|
355
|
+
if (!eligibility.serviceTier) return undefined;
|
|
320
356
|
state.lastInjectedAt = Date.now();
|
|
321
357
|
state.lastInjectedModel = eligibility.modelKey;
|
|
322
|
-
return { ...payload, service_tier:
|
|
358
|
+
return { ...payload, service_tier: eligibility.serviceTier };
|
|
323
359
|
}
|
|
324
360
|
|
|
325
361
|
export default function fastExtension(pi: ExtensionAPI) {
|
|
@@ -363,7 +399,7 @@ export default function fastExtension(pi: ExtensionAPI) {
|
|
|
363
399
|
});
|
|
364
400
|
|
|
365
401
|
pi.registerCommand("fast", {
|
|
366
|
-
description: "Toggle Fast mode for supported OpenAI Codex and Anthropic Claude models",
|
|
402
|
+
description: "Toggle Fast mode for supported direct OpenAI, OpenAI Codex, and Anthropic Claude models",
|
|
367
403
|
getArgumentCompletions: () => null,
|
|
368
404
|
handler: async (args, ctx) => {
|
|
369
405
|
const state = getState(ctx);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-fast",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "A pi extension that enables Fast mode for supported OpenAI Codex and Anthropic Claude models based on the currently selected model.",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "A pi extension that enables Fast mode for supported direct OpenAI API, OpenAI Codex, and Anthropic Claude models based on the currently selected model.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
7
7
|
"pi",
|
|
@@ -12,7 +12,7 @@ It replaces pi's built-in footer with a cleaner two-line layout that focuses on
|
|
|
12
12
|
- current context percentage
|
|
13
13
|
- red `DUMB ZONE` indicator when context usage is above 200k tokens
|
|
14
14
|
- current model and thinking level
|
|
15
|
-
- OpenAI Codex
|
|
15
|
+
- OpenAI Codex usage windows, labeled from the durations reported by OpenAI
|
|
16
16
|
- `xp` marker when Pi experimental features are enabled
|
|
17
17
|
|
|
18
18
|
## Layout
|
|
@@ -45,12 +45,14 @@ When context usage is above 200k tokens, the bottom-left line includes a red war
|
|
|
45
45
|
44.1% · DUMB ZONE
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
When using `openai-codex`, the bottom-left line also includes subscription usage:
|
|
48
|
+
When using `openai-codex`, the bottom-left line also includes subscription usage. A typical account with both windows looks like:
|
|
49
49
|
|
|
50
50
|
```text
|
|
51
51
|
44.1% · 5h 12% · 7d 38%
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
Window labels come from OpenAI's reported durations, so an account that reports only a weekly primary window is shown correctly (for example, `7d 38%`) instead of being assumed to have a 5-hour window.
|
|
55
|
+
|
|
54
56
|
When `PI_EXPERIMENTAL=1`, the bottom-left line also includes an experimental marker:
|
|
55
57
|
|
|
56
58
|
```text
|
|
@@ -116,11 +118,11 @@ Example:
|
|
|
116
118
|
"windows": {
|
|
117
119
|
"primary": {
|
|
118
120
|
"enabled": true,
|
|
119
|
-
"label": "
|
|
121
|
+
"label": "auto"
|
|
120
122
|
},
|
|
121
123
|
"secondary": {
|
|
122
124
|
"enabled": true,
|
|
123
|
-
"label": "
|
|
125
|
+
"label": "auto"
|
|
124
126
|
}
|
|
125
127
|
}
|
|
126
128
|
},
|
|
@@ -205,9 +207,9 @@ Disable git dirty/ahead/PR status:
|
|
|
205
207
|
- `codexUsage.cacheTtlMs`: in-memory usage cache duration
|
|
206
208
|
- `codexUsage.requestTimeoutMs`: usage request timeout
|
|
207
209
|
- `codexUsage.windows.primary.enabled`: show the primary usage window
|
|
208
|
-
- `codexUsage.windows.primary.label`:
|
|
210
|
+
- `codexUsage.windows.primary.label`: `"auto"` derives the primary label from OpenAI's reported duration; any other value overrides it
|
|
209
211
|
- `codexUsage.windows.secondary.enabled`: show the secondary usage window
|
|
210
|
-
- `codexUsage.windows.secondary.label`:
|
|
212
|
+
- `codexUsage.windows.secondary.label`: `"auto"` derives the secondary label from OpenAI's reported duration; any other value overrides it
|
|
211
213
|
- `experimentalMarker.enabled`: show the marker when `PI_EXPERIMENTAL=1`
|
|
212
214
|
- `experimentalMarker.label`: marker text
|
|
213
215
|
- `experimentalMarker.color`: theme color for the marker (`error`, `warning`, `accent`, `text`, or `dim`)
|
|
@@ -221,7 +223,7 @@ Disable git dirty/ahead/PR status:
|
|
|
221
223
|
- **Top left:** current git branch plus dirty/ahead/PR status when available
|
|
222
224
|
- **Top right:** current repo directory name
|
|
223
225
|
- **Bottom left:** current context usage percentage, plus red `DUMB ZONE` above 200k context tokens
|
|
224
|
-
- **Bottom left on `openai-codex`:** current context usage percentage plus
|
|
226
|
+
- **Bottom left on `openai-codex`:** current context usage percentage plus the Codex usage windows reported for the account
|
|
225
227
|
- **Bottom left with `PI_EXPERIMENTAL=1`:** current context usage percentage plus `xp`
|
|
226
228
|
- **Bottom right:** model id and thinking level
|
|
227
229
|
|
|
@@ -237,5 +239,5 @@ This extension also lives inside the broader [`pi-extensions`](../../README.md)
|
|
|
237
239
|
- Shows `DUMB ZONE` only while context usage is above 200k tokens.
|
|
238
240
|
- Shows the model id rather than a provider-specific display label.
|
|
239
241
|
- Shows `xp` when `PI_EXPERIMENTAL=1`.
|
|
240
|
-
- For `openai-codex`, reads pi's stored OAuth login and fetches usage from ChatGPT's backend usage endpoint.
|
|
242
|
+
- For `openai-codex`, reads pi's stored OAuth login and fetches usage from ChatGPT's backend usage endpoint. Window labels are inferred from each window's reported duration; missing or unrecognized durations use neutral `usage` labels rather than guessing from window position.
|
|
241
243
|
- Usage is cached briefly in memory and refreshed after turns.
|
|
@@ -5,6 +5,7 @@ import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
|
5
5
|
const PROVIDER_ID = "openai-codex";
|
|
6
6
|
|
|
7
7
|
interface WhamUsageWindow {
|
|
8
|
+
limit_window_seconds?: number;
|
|
8
9
|
reset_at?: number;
|
|
9
10
|
used_percent?: number;
|
|
10
11
|
}
|
|
@@ -18,6 +19,7 @@ interface WhamUsageResponse {
|
|
|
18
19
|
|
|
19
20
|
export interface UsageWindow {
|
|
20
21
|
usedPercent?: number;
|
|
22
|
+
windowSeconds?: number;
|
|
21
23
|
resetAt?: number;
|
|
22
24
|
}
|
|
23
25
|
|
|
@@ -43,6 +45,11 @@ function normalizeUsedPercent(value?: number): number | undefined {
|
|
|
43
45
|
return Math.min(100, Math.max(0, value));
|
|
44
46
|
}
|
|
45
47
|
|
|
48
|
+
function normalizeWindowSeconds(value?: number): number | undefined {
|
|
49
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return undefined;
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
|
|
46
53
|
function normalizeResetAt(value?: number): number | undefined {
|
|
47
54
|
if (typeof value !== "number" || !Number.isFinite(value)) return undefined;
|
|
48
55
|
return value * 1000;
|
|
@@ -51,9 +58,10 @@ function normalizeResetAt(value?: number): number | undefined {
|
|
|
51
58
|
function parseUsageWindow(window?: WhamUsageWindow): UsageWindow | undefined {
|
|
52
59
|
if (!window) return undefined;
|
|
53
60
|
const usedPercent = normalizeUsedPercent(window.used_percent);
|
|
61
|
+
const windowSeconds = normalizeWindowSeconds(window.limit_window_seconds);
|
|
54
62
|
const resetAt = normalizeResetAt(window.reset_at);
|
|
55
|
-
if (usedPercent === undefined && resetAt === undefined) return undefined;
|
|
56
|
-
return { usedPercent, resetAt };
|
|
63
|
+
if (usedPercent === undefined && windowSeconds === undefined && resetAt === undefined) return undefined;
|
|
64
|
+
return { usedPercent, windowSeconds, resetAt };
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
function parseUsageSnapshot(data: WhamUsageResponse): Omit<UsageSnapshot, "fetchedAt"> {
|
|
@@ -125,6 +133,36 @@ function formatUsagePercent(value?: number): string | undefined {
|
|
|
125
133
|
return `${Math.round(value)}%`;
|
|
126
134
|
}
|
|
127
135
|
|
|
136
|
+
// Primary/secondary describe positions, not fixed periods. Match each reported
|
|
137
|
+
// duration the same way Codex does, allowing small backend rounding differences.
|
|
138
|
+
const KNOWN_WINDOW_LABELS: ReadonlyArray<{ seconds: number; label: string }> = [
|
|
139
|
+
{ seconds: 5 * 60 * 60, label: "5h" },
|
|
140
|
+
{ seconds: 24 * 60 * 60, label: "1d" },
|
|
141
|
+
{ seconds: 7 * 24 * 60 * 60, label: "7d" },
|
|
142
|
+
{ seconds: 30 * 24 * 60 * 60, label: "30d" },
|
|
143
|
+
{ seconds: 365 * 24 * 60 * 60, label: "365d" },
|
|
144
|
+
];
|
|
145
|
+
|
|
146
|
+
function isApproximateWindow(actualSeconds: number, expectedSeconds: number): boolean {
|
|
147
|
+
return Math.abs(actualSeconds - expectedSeconds) <= expectedSeconds * 0.05;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function formatUsageWindowLabel(
|
|
151
|
+
window: UsageWindow | undefined,
|
|
152
|
+
configuredLabel: string,
|
|
153
|
+
fallbackLabel: string,
|
|
154
|
+
): string {
|
|
155
|
+
if (configuredLabel.toLowerCase() !== "auto") return configuredLabel;
|
|
156
|
+
const windowSeconds = window?.windowSeconds;
|
|
157
|
+
if (windowSeconds !== undefined) {
|
|
158
|
+
const knownWindow = KNOWN_WINDOW_LABELS.find(({ seconds }) =>
|
|
159
|
+
isApproximateWindow(windowSeconds, seconds)
|
|
160
|
+
);
|
|
161
|
+
if (knownWindow) return knownWindow.label;
|
|
162
|
+
}
|
|
163
|
+
return fallbackLabel;
|
|
164
|
+
}
|
|
165
|
+
|
|
128
166
|
export function isOpenAICodexProvider(provider?: string): boolean {
|
|
129
167
|
return provider === PROVIDER_ID;
|
|
130
168
|
}
|
|
@@ -139,8 +177,18 @@ export function formatUsageSummary(
|
|
|
139
177
|
const secondary = formatUsagePercent(snapshot.secondary?.usedPercent);
|
|
140
178
|
const parts: string[] = [];
|
|
141
179
|
|
|
142
|
-
if (windows.primary.enabled && primary)
|
|
143
|
-
|
|
180
|
+
if (windows.primary.enabled && primary) {
|
|
181
|
+
const label = formatUsageWindowLabel(snapshot.primary, windows.primary.label, "usage");
|
|
182
|
+
parts.push(`${label} ${primary}`);
|
|
183
|
+
}
|
|
184
|
+
if (windows.secondary.enabled && secondary) {
|
|
185
|
+
const label = formatUsageWindowLabel(
|
|
186
|
+
snapshot.secondary,
|
|
187
|
+
windows.secondary.label,
|
|
188
|
+
"secondary usage",
|
|
189
|
+
);
|
|
190
|
+
parts.push(`${label} ${secondary}`);
|
|
191
|
+
}
|
|
144
192
|
|
|
145
193
|
return parts.length > 0 ? parts.join(" · ") : undefined;
|
|
146
194
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-extensions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.71",
|
|
4
4
|
"description": "A collection of pi extensions and skills for annotation UIs, context management, workflow audits, contrarian review, review-comment triage, notifications, brrr push alerts, safety guards, GitHub research, repo-local knowledge, todos, tool rendering, model/provider helpers, and Xiaohei-style article illustrations.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|