@llblab/pi-kit 0.31.2 → 0.32.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/BACKLOG.md +1 -1
- package/CHANGELOG.md +4 -0
- package/README.md +4 -2
- package/node_modules/@llblab/pi-codex-usage/AGENTS.md +2 -1
- package/node_modules/@llblab/pi-codex-usage/CHANGELOG.md +4 -0
- package/node_modules/@llblab/pi-codex-usage/README.md +11 -9
- package/node_modules/@llblab/pi-codex-usage/lib/extension.ts +13 -10
- package/node_modules/@llblab/pi-codex-usage/lib/fast.ts +6 -5
- package/node_modules/@llblab/pi-codex-usage/lib/query.ts +4 -4
- package/node_modules/@llblab/pi-codex-usage/lib/status.ts +10 -10
- package/node_modules/@llblab/pi-codex-usage/lib/telegram.ts +1 -1
- package/node_modules/@llblab/pi-codex-usage/lib/usage.ts +2 -1
- package/node_modules/@llblab/pi-codex-usage/package.json +1 -1
- package/package.json +2 -2
package/BACKLOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Backlog
|
|
2
2
|
|
|
3
|
-
The 0.
|
|
3
|
+
The 0.32.0 composition advances Codex Usage to 0.13.0; package pins, resource order and bundled runtime ownership remain authoritative in `package.json`. Release outcomes belong in [CHANGELOG.md](./CHANGELOG.md).
|
|
4
4
|
|
|
5
5
|
## Carried checks
|
|
6
6
|
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@llblab/pi-kit` are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.32.0: OpenAI Subscription Quota Support
|
|
6
|
+
|
|
7
|
+
- `OpenAI Subscription Support`: Advances Codex Usage to `0.13.0`. ChatGPT subscription OAuth under `openai` now fetches Codex quotas without the legacy `openai-codex` provider; ordinary API-key auth is skipped. Both providers support terminal and Telegram status plus `/fast`, with preferences isolated by provider/model. Other pins, package membership, resources and load order are unchanged.
|
|
8
|
+
|
|
5
9
|
## 0.31.2: Telegram Restore Flow
|
|
6
10
|
|
|
7
11
|
- `Telegram Restore Flow`: Advances the exact Telegram pin to `0.54.4`. Restoring a Pi into a routing tab renames the tab to that Pi's Thread title and keeps the prompt it answers, since an input sent from `All` now moves into its routing tab on desktop and mobile alike. Routing menus disappear after every final choice, every client ends with one routing tab per `All` input, and the old tab is removed right after Pi answers. Other pins, package membership, resources and load order are unchanged.
|
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Package links lead to the owning repositories for usage, documentation, issues,
|
|
|
15
15
|
| [`@llblab/pi-actors`](https://github.com/llblab/pi-actors) | `0.54.0` | Inspectable local Runs, reusable Recipes, persistent tools, and delegation Skills |
|
|
16
16
|
| [`@llblab/pi-claude-usage`](https://github.com/llblab/pi-claude-usage) | `0.2.1` | Claude subscription quota status and shared per-model Fast toggle for Opus, mirrored in Telegram |
|
|
17
17
|
| [`@llblab/pi-clean-room`](https://github.com/llblab/pi-clean-room) | `0.3.0` | Isolated nested Pi TUI with named npm extensions and compatible model selection |
|
|
18
|
-
| [`@llblab/pi-codex-usage`](https://github.com/llblab/pi-codex-usage) | `0.
|
|
18
|
+
| [`@llblab/pi-codex-usage`](https://github.com/llblab/pi-codex-usage) | `0.13.0` | OpenAI/legacy Codex subscription quota and Business credit status, with persistent priority Fast toggle mirrored in Telegram |
|
|
19
19
|
| [`@llblab/pi-grow-loop`](https://github.com/llblab/pi-grow-loop) | `0.9.0` | Visible continuation scheduling and bounded worker Skills through compiled, manifest-owned resources |
|
|
20
20
|
| [`@llblab/pi-state-flow`](https://github.com/llblab/pi-state-flow) | `0.26.4` | Scoped context/memory compiler with step-independent current memory, stable Passive/Active modes and visible blocked-state status |
|
|
21
21
|
| [`@llblab/pi-telegram`](https://github.com/llblab/pi-telegram) | `0.54.4` | Telegram companion with live Thread rebinding, temporary routing tabs, Workspace Restore, follower Threads, Windows support, files, voice, and controls |
|
|
@@ -45,7 +45,9 @@ Prefer the kit instead of separately loading the same packages. If you already u
|
|
|
45
45
|
|
|
46
46
|
## Development
|
|
47
47
|
|
|
48
|
-
The `0.
|
|
48
|
+
The `0.32.0` composition advances Codex Usage to `0.13.0`: subscription OAuth under `openai` can fetch the existing Codex quota without the legacy `openai-codex` provider, while ordinary API-key credentials are skipped. Terminal status, Telegram quota/Fast status and `/fast` support both providers, with Fast preferences isolated by provider/model. Other pins, resource paths and load order are unchanged.
|
|
49
|
+
|
|
50
|
+
Telegram `0.54.4` moves an `All` input into its routing tab, renames a restored tab to its Pi's Thread title, keeps routing menus one-shot and removes the old tab right after Pi answers, and `0.54.3`, which keeps mobile Telegram to one routing tab per `All` input, on top of `0.54.2`: an idle connected session no longer writes to disk periodically (the update journal has its own lock instead of the `telegram.json` guard, the leader proves liveness over the bus instead of a two-second `state.json` heartbeat), followers go offline instead of looping when Threaded Mode is switched off, unverifiable ownership checks are recorded and tolerated, and cancelled Generative App methods cannot leave processes behind. Telegram 0.54 uses bus protocol v3: update every Pi process that runs pi-telegram together, because a 0.53.x follower cannot register with a 0.54 leader. State Flow stays at `0.26.4`; all other pins, resources and load order remain unchanged. Telegram runtime storage stays in `tmp/pi-telegram`. Drain the prompt queue or accept losing waiting work before reload/restart; damaged-state reset discards all profiles' runtime continuity. `npm run validate` checks exact installed pins, declared resources, dependency audit and bundled inventory. It does not certify installed-client rendering; carried checks remain in [Backlog](./BACKLOG.md).
|
|
49
51
|
|
|
50
52
|
```bash
|
|
51
53
|
npm install
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
- `Domain DAG`: `index.ts` only re-exports the extension and public contracts; `lib/extension.ts` composes the Pi extension. `lib/usage-store.ts` owns persistence/leadership, `lib/query.ts` owns quota I/O, `lib/usage.ts` owns normalized reports, `lib/status.ts` and `lib/status-format.ts` own local UI orchestration and formatting, `lib/telegram.ts` owns optional registration, and `lib/fast.ts` owns Codex Fast semantics/request adaptation. `@llblab/pi-command-fast` owns command arbitration and generic JSONC override editing. Keep dependency direction acyclic; do not import `index.ts` from `lib/` or mix Fast persistence into quota coordination. Place domain tests in `tests/<domain>.test.ts` (or a domain-prefixed focused integration test); use independent names such as `invariants.test.ts` only for cross-domain invariants.
|
|
6
6
|
- `Statusline-first scope`: Own usage state + usage mode: keep quota reporting zero-configuration and the optional Fast toggle focused on the existing terminal status.
|
|
7
7
|
- Trigger: Considering new commands, menus, persisted settings, or notification output.
|
|
8
|
-
- Action: Prefer deleting the surface unless it is required for the optimistic TUI status widget, the optional `pi-telegram` `/start` status-line mirror, or the existing argument-free `/fast` command. Register
|
|
8
|
+
- Action: Prefer deleting the surface unless it is required for the optimistic TUI status widget, the optional `pi-telegram` `/start` status-line mirror, or the existing argument-free `/fast` command. Register both `openai-codex` and `openai` provider handlers through `registerFastProvider` on session_start and release both on session_shutdown; never register `/fast` directly or filter Fast by model ID/auth. Fast persists solely as `serviceTier: "priority"` in the current provider/model override (never share preferences across providers with the same model ID); OFF deletes only that property. Preserve JSONC/unrelated settings, existing wire tiers, and usage refresh/Telegram. Apply lowercase ` fast` through the final terminal boundary; the optional Telegram row reads the active model's Fast preference at render time and appends plain-text ` fast` (or shows `fast` alone without quota). Toggle redraws without quota fetch or success notification. The library owns session WeakMap/reload arbitration, not Fast state. A Fast config read failure must not block usage status.
|
|
9
|
+
- `OpenAI provider support`: Show the same Codex subscription quota for active `openai-codex` and `openai` models. Quota transport accepts `openai` subscription OAuth (guarded by `modelRegistry.isUsingOAuth`) and legacy `openai-codex` auth, with the Codex CLI fallback; never send `openai` API-key credentials to the ChatGPT quota endpoint or label Codex quotas as API billing limits.
|
|
9
10
|
- `Optimistic refresh`: Preserve the last good statusline bar during refresh and transient failures.
|
|
10
11
|
- Trigger: Updating quota polling or error handling.
|
|
11
12
|
- Action: Do not collapse the bar while a request is in flight; only show `n/a` or `error` after repeated failures or no usable quota.
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.13.0: OpenAI Subscription Provider Support
|
|
4
|
+
|
|
5
|
+
- Added `openai` alongside `openai-codex` for `/fast`, request priority adaptation, terminal status and the optional Telegram row. Fast preferences remain isolated by provider/model, including identical model IDs. Both providers share the existing Codex subscription quota stream. Pi subscription OAuth under `openai` now fetches quota directly without requiring the legacy provider; `openai` API-key auth is skipped and the Codex CLI fallback is preserved.
|
|
6
|
+
|
|
3
7
|
## 0.12.1: Telegram Fast Status
|
|
4
8
|
|
|
5
9
|
- The optional Telegram status row now appends lowercase ` fast` for the active Codex model, or shows `fast` alone when quota is unavailable. It rereads the per-model preference at menu render time, so toggles, model changes and manual edits do not wait for quota refresh. Quota polling, auth, request adaptation and terminal behavior are unchanged; isolated tests cover enabled/disabled state, model/provider changes and unreadable configuration.
|
|
@@ -19,16 +19,16 @@ This repository is a minimal fork of [`narumiruna/pi-extensions/extensions/pi-co
|
|
|
19
19
|
- Shows two counter-moving half-height markers in the statusline bar while Codex usage is loading, then keeps the bar fresh (the countdown ticks locally)
|
|
20
20
|
- Keeps the last usable bar visible during ordinary refreshes instead of replacing known quota with a loading state
|
|
21
21
|
- Statusline output adapts to the response: weekly-only limits show an explicit remaining percentage and reset countdown, while dual-window limits keep the compact themed bar
|
|
22
|
-
-
|
|
23
|
-
- When `pi-telegram` is available, the same compact value appears as `codex: <value>` in the `/start` menu status text for
|
|
22
|
+
- Models under either `openai-codex` or `openai` show the same primary Codex subscription quota and `codex` status label (not OpenAI API billing limits)
|
|
23
|
+
- When `pi-telegram` is available, the same compact value appears as `codex: <value>` in the `/start` menu status text for either supported provider
|
|
24
24
|
- Additional returned quota buckets are ignored
|
|
25
|
-
- Pi
|
|
25
|
+
- Pi subscription auth from `openai` or legacy `openai-codex` is used first
|
|
26
26
|
- Codex CLI app-server remains available as a fallback
|
|
27
27
|
- Missing auth, subscription, plan, or quota windows are shown as `n/a`, not as an error
|
|
28
28
|
- Successful updates briefly redraw the bar only when a 5% segment changes
|
|
29
29
|
- Network/provider failures keep the last good bar (up to an hour), then show `error`
|
|
30
30
|
- Any number of Pi instances share one request stream, see [Shared Refresh](#shared-refresh)
|
|
31
|
-
- Quota display requires no configuration; `/fast` optionally toggles priority service for the active
|
|
31
|
+
- Quota display requires no configuration; `/fast` optionally toggles priority service for the active `openai-codex` or `openai` model
|
|
32
32
|
|
|
33
33
|
## Install
|
|
34
34
|
|
|
@@ -59,7 +59,7 @@ For explicitly local library experiments, a temporary folder link reads the libr
|
|
|
59
59
|
|
|
60
60
|
## Fast mode
|
|
61
61
|
|
|
62
|
-
`/fast` takes no arguments and dispatches by the current **provider**, not model names or OAuth eligibility. For any `openai-codex` model, it stores only `serviceTier: "priority"` in Pi's canonical `models.json` (honoring `PI_CODING_AGENT_DIR`):
|
|
62
|
+
`/fast` takes no arguments and dispatches by the current **provider**, not model names or OAuth eligibility. For any `openai-codex` or `openai` model, it stores only `serviceTier: "priority"` in Pi's canonical `models.json` (honoring `PI_CODING_AGENT_DIR`):
|
|
63
63
|
|
|
64
64
|
```json
|
|
65
65
|
{
|
|
@@ -73,6 +73,8 @@ For explicitly local library experiments, a temporary folder link reads the libr
|
|
|
73
73
|
}
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
+
For an `openai` model, the same override goes under `providers.openai.modelOverrides`. Preferences are isolated by provider and model ID, so identical IDs in the two providers do not share Fast state.
|
|
77
|
+
|
|
76
78
|
OFF removes only `serviceTier`; it never writes `"default"`. JSONC comments and unrelated configuration survive. There is no separate Fast config or model allowlist. State follows provider/model selection and survives restart; manual edits are read on lifecycle refresh and each request.
|
|
77
79
|
|
|
78
80
|
When this and Claude Usage are loaded, their shared library registers **one** `/fast`, in either load order, even with separate physical dependency copies. A session-scoped WeakMap avoids cross-session dispatch; shutdown releases registrations for reload (Pi retains the session manager). Unrelated providers receive a concise unsupported-provider message. Invalid arguments show `Usage: /fast`; success is silent.
|
|
@@ -155,22 +157,22 @@ Coordination assumes a local filesystem and cooperating instances on the same ma
|
|
|
155
157
|
|
|
156
158
|
## Telegram Status Menu
|
|
157
159
|
|
|
158
|
-
If `@llblab/pi-telegram` is loaded with the public status-line provider API, this extension registers an optional `/start` menu status row. The row is shown only while the active model uses
|
|
160
|
+
If `@llblab/pi-telegram` is loaded with the public status-line provider API, this extension registers an optional `/start` menu status row. The row is shown only while the active model uses `openai-codex` or `openai`:
|
|
159
161
|
|
|
160
162
|
```text
|
|
161
163
|
codex: ██████▀▀▀▀ 6d
|
|
162
164
|
```
|
|
163
165
|
|
|
164
|
-
The value is the same compact quota bar plus weekly reset countdown used by the terminal statusline, always with the `codex` label. When Fast is enabled for the active model, it appends plain-text ` fast`; without a usable quota report it shows `codex: fast`. The preference is reread when the menu is rendered, so toggles and model changes do not depend on a quota refresh. If `pi-telegram` is absent, older, or the active model
|
|
166
|
+
The value is the same compact quota bar plus weekly reset countdown used by the terminal statusline, always with the `codex` label. When Fast is enabled for the active model, it appends plain-text ` fast`; without a usable quota report it shows `codex: fast`. The preference is reread when the menu is rendered, so toggles and model changes do not depend on a quota refresh. If `pi-telegram` is absent, older, or the active model uses another provider, no Telegram row is added.
|
|
165
167
|
|
|
166
168
|
## Auth
|
|
167
169
|
|
|
168
170
|
The extension tries usage sources in this order:
|
|
169
171
|
|
|
170
|
-
1. Pi's `openai-codex`
|
|
172
|
+
1. Pi's subscription auth from `openai` or legacy `openai-codex` (active model first)
|
|
171
173
|
2. `codex app-server --listen stdio://`
|
|
172
174
|
|
|
173
|
-
OpenAI API keys are not ChatGPT
|
|
175
|
+
Selecting an `openai` model enables the status and Fast toggle, and its ChatGPT subscription OAuth credentials can fetch the quota directly; a legacy `openai-codex` provider is not required. The extension uses Pi's resolved auth headers/token, checks `modelRegistry.isUsingOAuth` before using `openai` credentials, and keeps the Codex CLI fallback. OpenAI API keys are not ChatGPT subscription auth and do not expose these quotas; `openai` API-key credentials are skipped, not sent to the ChatGPT quota endpoint. Without subscription auth/quota, the quota status is `n/a` when both sources report an unavailable state. Fast works independently of subscription auth.
|
|
174
176
|
|
|
175
177
|
## License
|
|
176
178
|
|
|
@@ -3,23 +3,26 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
|
3
3
|
import { registerFastProvider } from "@llblab/pi-command-fast";
|
|
4
4
|
import { applyFastToRequest, isFastEnabled, isFastEligibleModel, toggleFast } from "./fast.ts";
|
|
5
5
|
import { createCodexUsageStatus } from "./status.ts";
|
|
6
|
+
import { OPENAI_USAGE_PROVIDERS } from "./usage.ts";
|
|
6
7
|
|
|
7
8
|
export default function codexUsage(pi: ExtensionAPI) {
|
|
8
|
-
let releaseFast: (
|
|
9
|
+
let releaseFast: Array<() => void> = [];
|
|
9
10
|
pi.on("session_start", (_event, ctx) => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
for (const provider of OPENAI_USAGE_PROVIDERS) {
|
|
12
|
+
releaseFast.push(registerFastProvider(pi, ctx, {
|
|
13
|
+
provider,
|
|
14
|
+
toggle(commandCtx) {
|
|
15
|
+
toggleFast(commandCtx.model!);
|
|
16
|
+
status.fastChanged(commandCtx, commandCtx.model!);
|
|
17
|
+
},
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
17
20
|
});
|
|
18
|
-
pi.on("session_shutdown", () => { releaseFast
|
|
21
|
+
pi.on("session_shutdown", () => { releaseFast.forEach((release) => release()); releaseFast = []; });
|
|
19
22
|
const status = createCodexUsageStatus(pi);
|
|
20
23
|
pi.on("before_provider_request", (event, ctx) => {
|
|
21
24
|
const model = ctx.model;
|
|
22
25
|
if (!isFastEligibleModel(model)) return;
|
|
23
|
-
return applyFastToRequest(event.payload, model.id, isFastEnabled(model
|
|
26
|
+
return applyFastToRequest(event.payload, model.id, isFastEnabled(model));
|
|
24
27
|
});
|
|
25
28
|
}
|
|
@@ -3,16 +3,17 @@ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
|
3
3
|
import { isModelOverrideValue, toggleModelOverrideValue } from "@llblab/pi-command-fast";
|
|
4
4
|
import { isOpenAICodexModel } from "./usage.ts";
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
type FastModel = Pick<NonNullable<ExtensionContext["model"]>, "provider" | "id">;
|
|
7
|
+
const target = (model: FastModel) => ({ provider: model.provider, id: model.id, property: "serviceTier", enabledValue: "priority" });
|
|
7
8
|
|
|
8
9
|
export function isFastEligibleModel(model: ExtensionContext["model"]): model is NonNullable<ExtensionContext["model"]> {
|
|
9
10
|
return !!model && isOpenAICodexModel(model);
|
|
10
11
|
}
|
|
11
|
-
export function isFastEnabled(
|
|
12
|
-
return isModelOverrideValue(target(
|
|
12
|
+
export function isFastEnabled(model: FastModel, path?: string): boolean {
|
|
13
|
+
return isModelOverrideValue(target(model), path);
|
|
13
14
|
}
|
|
14
|
-
export function toggleFast(
|
|
15
|
-
return toggleModelOverrideValue(target(
|
|
15
|
+
export function toggleFast(model: FastModel, path?: string): boolean {
|
|
16
|
+
return toggleModelOverrideValue(target(model), path);
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export function applyFastToRequest(payload: unknown, modelId: string, enabled: boolean): unknown {
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
import { type ChildProcessWithoutNullStreams, spawn } from "node:child_process";
|
|
3
3
|
import { createInterface } from "node:readline";
|
|
4
4
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
5
|
-
import { assertObject, errorMessage, normalizeAppServerResponse, normalizeBackendPayload, parseJsonObject, selectUsageSnapshot, type AppServerRateLimitResponse, type CodexUsageModel, type CodexUsageReport, type RateLimitStatusPayload, type UsageQueryError } from "./usage.ts";
|
|
6
|
-
const CODEX_PROVIDER_ID = "openai-codex";
|
|
5
|
+
import { assertObject, errorMessage, isOpenAICodexModel, normalizeAppServerResponse, normalizeBackendPayload, parseJsonObject, selectUsageSnapshot, type AppServerRateLimitResponse, type CodexUsageModel, type CodexUsageReport, type RateLimitStatusPayload, type UsageQueryError } from "./usage.ts";
|
|
7
6
|
const CODEX_USAGE_LIMIT_ID = "codex";
|
|
8
7
|
const CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
|
|
9
8
|
const MAX_ERROR_BODY_CHARS = 600;
|
|
@@ -64,7 +63,7 @@ async function queryViaPiAuth(
|
|
|
64
63
|
const auth = await resolvePiCodexAuth(ctx);
|
|
65
64
|
if (!auth) {
|
|
66
65
|
throw new Error(
|
|
67
|
-
"No Pi OpenAI Codex subscription auth was available. Use
|
|
66
|
+
"No Pi OpenAI Codex subscription auth was available. Use an openai or openai-codex subscription model or run /login for OpenAI ChatGPT.",
|
|
68
67
|
);
|
|
69
68
|
}
|
|
70
69
|
|
|
@@ -96,6 +95,7 @@ async function resolvePiCodexAuth(
|
|
|
96
95
|
const errors: string[] = [];
|
|
97
96
|
|
|
98
97
|
for (const model of models) {
|
|
98
|
+
if (model.provider === "openai" && !ctx.modelRegistry.isUsingOAuth(model)) continue;
|
|
99
99
|
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
|
|
100
100
|
if (!auth.ok) {
|
|
101
101
|
errors.push(auth.error);
|
|
@@ -127,7 +127,7 @@ function codexAuthCandidateModels(ctx: ExtensionContext): PiModel[] {
|
|
|
127
127
|
const candidates: PiModel[] = [];
|
|
128
128
|
const seen = new Set<string>();
|
|
129
129
|
const add = (model: PiModel | undefined) => {
|
|
130
|
-
if (!model || model
|
|
130
|
+
if (!model || !isOpenAICodexModel(model)) return;
|
|
131
131
|
const key = `${model.provider}/${model.id}`;
|
|
132
132
|
if (seen.has(key)) return;
|
|
133
133
|
seen.add(key);
|
|
@@ -41,20 +41,20 @@ export function createCodexUsageStatus(pi: ExtensionAPI) {
|
|
|
41
41
|
let statuslineRequestId = 0;
|
|
42
42
|
let unregisterTelegramStatusLine: (() => void) | undefined;
|
|
43
43
|
let telegramStatusLineRegistration: Promise<void> | undefined;
|
|
44
|
-
let
|
|
44
|
+
let fastModel: PiModel | undefined;
|
|
45
45
|
let fastEnabled = false;
|
|
46
46
|
let lastStatusText: string | undefined;
|
|
47
47
|
let loadingModel: CodexUsageModel | undefined;
|
|
48
48
|
|
|
49
|
-
const syncFast = (model: PiModel | undefined
|
|
50
|
-
|
|
51
|
-
fastEnabled =
|
|
49
|
+
const syncFast = (model: PiModel | undefined) => {
|
|
50
|
+
fastModel = isFastEligibleModel(model) ? model : undefined;
|
|
51
|
+
fastEnabled = fastModel !== undefined && isFastEnabled(fastModel);
|
|
52
52
|
};
|
|
53
53
|
const setCodexStatus = (ctx: ExtensionContext, text: string | undefined, model?: CodexUsageModel) => {
|
|
54
54
|
lastStatusText = text;
|
|
55
55
|
ctx.ui.setStatus(STATUS_KEY, text === undefined ? undefined : appendFastStatus(
|
|
56
56
|
ctx, text,
|
|
57
|
-
fastEnabled && model?.id ===
|
|
57
|
+
fastEnabled && model?.provider === fastModel?.provider && model?.id === fastModel?.id,
|
|
58
58
|
));
|
|
59
59
|
};
|
|
60
60
|
|
|
@@ -95,7 +95,7 @@ export function createCodexUsageStatus(pi: ExtensionAPI) {
|
|
|
95
95
|
ctx: ExtensionContext,
|
|
96
96
|
model: CodexUsageModel | undefined,
|
|
97
97
|
) => {
|
|
98
|
-
const modelChanged = loadingModel?.id !== model?.id;
|
|
98
|
+
const modelChanged = loadingModel?.provider !== model?.provider || loadingModel?.id !== model?.id;
|
|
99
99
|
loadingModel = model;
|
|
100
100
|
if (statuslineLoadingTimer) {
|
|
101
101
|
if (modelChanged && lastStatusText !== undefined) setCodexStatus(ctx, lastStatusText, model);
|
|
@@ -331,7 +331,7 @@ export function createCodexUsageStatus(pi: ExtensionAPI) {
|
|
|
331
331
|
try {
|
|
332
332
|
const activeModel = model ?? ctx.model;
|
|
333
333
|
const previousFast = fastEnabled;
|
|
334
|
-
syncFast(activeModel
|
|
334
|
+
syncFast(activeModel);
|
|
335
335
|
forceRender ||= previousFast !== fastEnabled;
|
|
336
336
|
if (!isOpenAICodexModel(activeModel)) {
|
|
337
337
|
clearUsageStatusline(ctx);
|
|
@@ -370,7 +370,7 @@ export function createCodexUsageStatus(pi: ExtensionAPI) {
|
|
|
370
370
|
ensureTelegramStatusLineRegistered();
|
|
371
371
|
|
|
372
372
|
pi.on("session_start", (_event, ctx) => {
|
|
373
|
-
syncFast(ctx.model
|
|
373
|
+
syncFast(ctx.model);
|
|
374
374
|
ensureTelegramStatusLineRegistered();
|
|
375
375
|
if (isOpenAICodexModel(ctx.model))
|
|
376
376
|
void refreshCurrentCodexUsageStatusline(ctx, true).catch(
|
|
@@ -388,7 +388,7 @@ export function createCodexUsageStatus(pi: ExtensionAPI) {
|
|
|
388
388
|
});
|
|
389
389
|
|
|
390
390
|
pi.on("model_select", (event, ctx) => {
|
|
391
|
-
syncFast(event.model
|
|
391
|
+
syncFast(event.model);
|
|
392
392
|
if (isOpenAICodexModel(event.model)) {
|
|
393
393
|
void refreshCurrentCodexUsageStatusline(ctx, true, event.model).catch(
|
|
394
394
|
handleAsyncTimerError,
|
|
@@ -405,7 +405,7 @@ export function createCodexUsageStatus(pi: ExtensionAPI) {
|
|
|
405
405
|
});
|
|
406
406
|
return {
|
|
407
407
|
fastChanged(ctx: ExtensionContext, model: PiModel) {
|
|
408
|
-
syncFast(model
|
|
408
|
+
syncFast(model);
|
|
409
409
|
if (lastStatusText !== undefined) setCodexStatus(ctx, lastStatusText, model);
|
|
410
410
|
renderState(ctx, loadState(), model, true);
|
|
411
411
|
},
|
|
@@ -29,7 +29,7 @@ export function codexUsageTelegramStatusLine(
|
|
|
29
29
|
): TelegramStatusLineProviderResult {
|
|
30
30
|
if (!activeModel || !isOpenAICodexModel(activeModel)) return undefined;
|
|
31
31
|
const value = report ? formatCodexUsageStatusValue(report, activeModel) : undefined;
|
|
32
|
-
const fast = isFastEnabled(activeModel
|
|
32
|
+
const fast = isFastEnabled(activeModel);
|
|
33
33
|
if (!value && !fast) return undefined;
|
|
34
34
|
return { label: "codex", value: value ? `${value}${fast ? " fast" : ""}` : "fast" };
|
|
35
35
|
}
|
|
@@ -4,8 +4,9 @@ const SECOND_MS = 1000;
|
|
|
4
4
|
const CODEX_USAGE_LIMIT_ID = "codex";
|
|
5
5
|
type PiModel = NonNullable<ExtensionContext["model"]>;
|
|
6
6
|
export type CodexUsageModel = Pick<PiModel, "id" | "name" | "provider">;
|
|
7
|
+
export const OPENAI_USAGE_PROVIDERS = ["openai-codex", "openai"] as const;
|
|
7
8
|
export function isOpenAICodexModel(model: Pick<PiModel, "provider"> | undefined): boolean {
|
|
8
|
-
return model?.provider ===
|
|
9
|
+
return OPENAI_USAGE_PROVIDERS.some((provider) => model?.provider === provider);
|
|
9
10
|
}
|
|
10
11
|
export type UsageSource = "pi-auth" | "codex-app-server";
|
|
11
12
|
export type UsageQueryError = { source: UsageSource; message: string; cause?: unknown };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llblab/pi-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@llblab/pi-actors": "0.54.0",
|
|
45
45
|
"@llblab/pi-claude-usage": "0.2.1",
|
|
46
46
|
"@llblab/pi-clean-room": "0.3.0",
|
|
47
|
-
"@llblab/pi-codex-usage": "0.
|
|
47
|
+
"@llblab/pi-codex-usage": "0.13.0",
|
|
48
48
|
"@llblab/pi-grow-loop": "0.9.0",
|
|
49
49
|
"@llblab/pi-state-flow": "0.26.4",
|
|
50
50
|
"@llblab/pi-telegram": "0.54.4",
|