@monotykamary/pi-better-openai 0.2.10 → 0.2.12
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/CHANGELOG.md +14 -0
- package/README.md +11 -7
- package/package.json +6 -6
- package/src/codex-auth.ts +5 -0
- package/src/config.ts +1 -1
- package/src/fast-controller.ts +3 -2
- package/src/image.ts +2 -1
- package/src/live/transport.ts +2 -2
- package/src/reset-controller.ts +8 -6
- package/src/resets.ts +4 -5
- package/src/usage-controller.ts +21 -11
- package/src/websearch.ts +6 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.12
|
|
4
|
+
|
|
5
|
+
- Validate against Pi 1.0.2, where `openai` supports ChatGPT subscription OAuth and `openai-codex` is labeled legacy; preserve the native OpenAI provider and transport.
|
|
6
|
+
- Keep Ultrafast API-only: do not inject it for the new OpenAI subscription login, and retain Standard/Fast behavior.
|
|
7
|
+
- Label separately authenticated Codex usage on OpenAI models and warn that it is not verified against the active OpenAI account.
|
|
8
|
+
- Clarify that usage, banked resets, images, web search, and live voice still need `/login openai-codex`; never substitute direct-OpenAI OAuth credentials for Codex backend auth.
|
|
9
|
+
- Add auth-boundary regressions and an isolated real-host subscription/API-key compatibility probe.
|
|
10
|
+
|
|
11
|
+
## 0.2.11
|
|
12
|
+
|
|
13
|
+
- Auto-redeem banked Codex resets ten minutes before expiry instead of one minute, with matching settings and redemption-time displays.
|
|
14
|
+
- Preserve the scheduled credit across polling refreshes so the longer lead retains the no-fallback safeguard.
|
|
15
|
+
- Extend the shared redemption cooldown to ten minutes and add regression coverage for exact timing and startup inside the redemption window.
|
|
16
|
+
|
|
3
17
|
## 0.2.10
|
|
4
18
|
|
|
5
19
|
- Hide disabled image, web search, and decision tools and their prompt guidance, including from pi-fabric capture.
|
package/README.md
CHANGED
|
@@ -20,13 +20,15 @@ pi install npm:@monotykamary/pi-better-openai
|
|
|
20
20
|
|
|
21
21
|
## Authentication
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Pi 1.0.2 supports **Sign in with ChatGPT** under `/login openai`, using the native Responses API at `api.openai.com`. Use `openai/*` models for that subscription login or an OpenAI API key; the extension preserves pi's native authentication and transport. Standard/Fast tier overrides work with both login methods on supported models.
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
Pi labels `openai-codex` **legacy**, but this extension's usage polling, banked resets, image generation, web search, and live voice still call separate `chatgpt.com/backend-api` endpoints. They require the legacy Codex login, not the new direct-OpenAI OAuth grant. Credentials are never copied or substituted between providers.
|
|
26
|
+
|
|
27
|
+
1. For those backend features, also run `/login openai-codex`. You can keep an `openai/*` model selected.
|
|
28
|
+
2. Inspect the Codex account's usage with `/openai-usage`, or open `/openai-settings` and check **Diagnostics**. While using `openai/*`, the footer labels it **Codex Usage**: it is not verified against your active OpenAI login and could belong to a different account. For your OpenAI subscription, check [ChatGPT usage](https://chatgpt.com/settings/usage).
|
|
27
29
|
3. The extension reads auth from pi's agent auth store, normally `~/.pi/agent/auth.json`. Do not copy, paste, or commit values from this file.
|
|
28
30
|
4. If `PI_CODING_AGENT_DIR` is set, the auth store, global extension config, and global generated-image directory use that agent directory instead of `~/.pi/agent`. A leading `~/` is expanded to your home directory.
|
|
29
|
-
5. When [pi-multiprovider](https://github.com/monotykamary/pi-multiprovider) 0.8.0+ pools several `openai-codex` accounts, the session's active account (chosen with `/switch-account`) is resolved first for usage display, image generation, web search, and live voice; the usage widget refreshes on
|
|
31
|
+
5. When [pi-multiprovider](https://github.com/monotykamary/pi-multiprovider) 0.8.0+ pools several `openai-codex` accounts, the session's active **Codex** account (chosen with `/switch-account`) is resolved first for usage display, banked resets, image generation, web search, and live voice; the usage widget refreshes on Codex account switches and session restores. An independently selected `openai` account does not select the Codex backend account. Without that extension, credential resolution is unchanged.
|
|
30
32
|
|
|
31
33
|
## Features
|
|
32
34
|
|
|
@@ -54,9 +56,9 @@ Usage display, image generation, and live voice require pi's `openai-codex` OAut
|
|
|
54
56
|
|
|
55
57
|
## Banked resets
|
|
56
58
|
|
|
57
|
-
Unused banked Codex resets **auto-redeem by default,
|
|
59
|
+
Unused banked Codex resets **auto-redeem by default, 10 minutes before expiry**, while an interactive pi session is running and Codex credentials are available. Starting pi within that final ten-minute window also triggers the check; expired credits are skipped. This runs independently of the usage display and current model. The reset picker and confirmation show each credit's actual local auto-redemption date and time (expiry minus ten minutes) beside its expiry. Disable **Auto-redeem banked resets** in `/openai-settings` or set `usage.autoRedeemBankedResets` to `false` to opt out.
|
|
58
60
|
|
|
59
|
-
For safety, each attempt targets one explicit, freshly checked credit ID, with no fallback to another credit and no automatic retry after a consume request (including errors or `nothing_to_reset`). A persistent per-account guard permits at most one redemption attempt in
|
|
61
|
+
For safety, each attempt targets one explicit, freshly checked credit ID, with no fallback to another credit and no automatic retry after a consume request (including errors or `nothing_to_reset`). A persistent per-account guard permits at most one redemption attempt in ten minutes across pi sessions sharing the same agent directory; manual redemption uses the same guard. Automatic reservations recheck the ten-minute eligibility window while holding an exclusive filesystem lock, and attempted credit IDs remain blocked even after later redemptions or restarts. Simultaneously expiring credits are not drained, and later credits wait for their own final ten-minute window. Reservations live under `$PI_CODING_AGENT_DIR/pi-better-openai/reset-redemptions` (default `~/.pi/agent/pi-better-openai/reset-redemptions`); unreadable state or an orphaned lock blocks redemption rather than risking a duplicate. Update/restart all pi instances to use the current guard. Separate machines/agent directories cannot coordinate this local guard; instances using the same account should share an agent directory.
|
|
60
62
|
|
|
61
63
|
Pi must remain running and awake; this is not an OS-level scheduled task. No eligible usage window or unavailable credentials can prevent redemption.
|
|
62
64
|
|
|
@@ -145,7 +147,7 @@ Setting `image.enabled`, `websearch.enabled`, or `decisions.enabled` to `false`
|
|
|
145
147
|
|
|
146
148
|
`/openai-tier fast` requests `service_tier: "priority"`. `/openai-tier standard` explicitly requests `"default"`, clearing an inherited Fast/Ultrafast request tier on OpenAI providers. Legacy disabled configurations without an explicit tier leave payloads untouched. `/fast` and the `--fast` flag never select Ultrafast.
|
|
147
149
|
|
|
148
|
-
`/openai-tier ultrafast` explicitly opts into **6x Standard token prices** for `openai/gpt-6-astra` over the Responses API. Only the documented global (`https://api.openai.com/v1`) and US (`https://us.api.openai.com/v1`) endpoints are enabled. EU/regional endpoints, custom proxies, other models, and
|
|
150
|
+
`/openai-tier ultrafast` explicitly opts into **6x Standard token prices** for **API-key-authenticated** `openai/gpt-6-astra` over the Responses API. Only the documented global (`https://api.openai.com/v1`) and US (`https://us.api.openai.com/v1`) endpoints are enabled. EU/regional endpoints, custom proxies, other models, and ChatGPT subscription Ultrafast (both `openai` OAuth and legacy `openai-codex`) are not enabled without verified support. This does not promise account entitlement or available rate limits. Unsupported selections remain requested but inactive; the extension does not inject a lower-tier fallback or retry a rejected request.
|
|
149
151
|
|
|
150
152
|
The footer shows `fast` or `ultrafast` only when supported by the current model. Diagnostics distinguish the requested tier and last injected payload from server-confirmed service or billing. **Pi's host cost estimates may omit the Ultrafast premium**; use OpenAI billing for actual charges. The host's native transport is preserved; WebSockets are recommended by OpenAI but HTTP is also supported. See [Ultrafast documentation](https://developers.openai.com/api/docs/guides/ultrafast-mode) and [pricing](https://developers.openai.com/api/docs/pricing?latest-pricing=ultrafast).
|
|
151
153
|
|
|
@@ -188,6 +190,8 @@ Example tool input:
|
|
|
188
190
|
|
|
189
191
|
## Codex model fallbacks
|
|
190
192
|
|
|
193
|
+
These fallbacks remain scoped to the legacy provider. The native `openai` provider and its catalog are not replaced or redirected to Codex.
|
|
194
|
+
|
|
191
195
|
The extension adds `gpt-6.1-sol`, `gpt-6-astra`, `gpt-daybreak-blue-latest`, and `gpt-daybreak-red-latest` to the built-in `openai-codex` provider without requiring local `models.json` entries. Existing built-in models remain available, and metadata from pi's live catalog takes precedence when pi publishes an official entry with the same ID.
|
|
192
196
|
|
|
193
197
|
The GPT-6.1 Sol fallback uses Codex's conservative 272K context default, 128K output limit, and published short/long-context pricing. It maps Pi's `minimal` level to `low` and disables `off`; the model does not accept `none` or `minimal` reasoning efforts. See [model documentation](https://developers.openai.com/api/docs/models/gpt-6.1-sol) and the [upstream Codex catalog change](https://github.com/openai/codex/commit/b1e72963c3b71a9265a551e54beff078384efed9).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monotykamary/pi-better-openai",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.12",
|
|
4
4
|
"description": "Improve OpenAI in pi with fast mode, usage stats, realtime voice, image generation, and footer polish.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fast",
|
|
@@ -65,9 +65,9 @@
|
|
|
65
65
|
"ws": "8.21.2"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"@earendil-works/pi-ai": "1.0.
|
|
69
|
-
"@earendil-works/pi-coding-agent": "1.0.
|
|
70
|
-
"@earendil-works/pi-tui": "1.0.
|
|
68
|
+
"@earendil-works/pi-ai": "1.0.2",
|
|
69
|
+
"@earendil-works/pi-coding-agent": "1.0.2",
|
|
70
|
+
"@earendil-works/pi-tui": "1.0.2",
|
|
71
71
|
"@types/node": "~22.19.0",
|
|
72
72
|
"@types/proxy-from-env": "1.0.4",
|
|
73
73
|
"@types/ws": "8.18.1",
|
|
@@ -89,8 +89,8 @@
|
|
|
89
89
|
"@oh-my-pi/pi-natives-win32-x64": "17.2.9"
|
|
90
90
|
},
|
|
91
91
|
"overrides": {
|
|
92
|
-
"@earendil-works/pi-agent-core": "1.0.
|
|
93
|
-
"@earendil-works/pi-ai": "1.0.
|
|
92
|
+
"@earendil-works/pi-agent-core": "1.0.2",
|
|
93
|
+
"@earendil-works/pi-ai": "1.0.2",
|
|
94
94
|
"brace-expansion": "5.0.11",
|
|
95
95
|
"nanoid": "3.3.18",
|
|
96
96
|
"postcss": "8.5.25",
|
package/src/codex-auth.ts
CHANGED
|
@@ -6,6 +6,9 @@ import { piAgentDir } from "./paths.ts";
|
|
|
6
6
|
|
|
7
7
|
export const AUTH_FILE = join(piAgentDir(), "auth.json");
|
|
8
8
|
|
|
9
|
+
export const CODEX_AUTH_REQUIRED =
|
|
10
|
+
"Missing openai-codex OAuth credentials. Run /login openai-codex for this Codex backend feature. /login openai uses separate ChatGPT subscription credentials for api.openai.com.";
|
|
11
|
+
|
|
9
12
|
export type CodexCredentials = {
|
|
10
13
|
accessToken: string;
|
|
11
14
|
accountId: string;
|
|
@@ -145,6 +148,8 @@ export async function getCodexCredentials(
|
|
|
145
148
|
// Fall back to pi-owned credential resolution.
|
|
146
149
|
}
|
|
147
150
|
}
|
|
151
|
+
// Deliberately do not fall back to "openai": its direct ChatGPT OAuth grant
|
|
152
|
+
// targets api.openai.com, not the legacy chatgpt.com/backend-api endpoints.
|
|
148
153
|
const registryRequest = ctx?.modelRegistry?.getApiKeyForProvider(CODEX_PROVIDER_ID);
|
|
149
154
|
const registryToken = registryRequest
|
|
150
155
|
? await waitForSignal(
|
package/src/config.ts
CHANGED
|
@@ -410,7 +410,7 @@ export const USAGE_SETTING_DESCRIPTORS: readonly SettingsOptionDescriptor[] = [
|
|
|
410
410
|
label: "Auto-redeem banked resets",
|
|
411
411
|
currentValue: (cfg) => String(cfg.usage.autoRedeemBankedResets),
|
|
412
412
|
values: ["true", "false"],
|
|
413
|
-
description: "Redeem one unused banked reset
|
|
413
|
+
description: "Redeem one unused banked reset 10 minutes before expiry while pi is running.",
|
|
414
414
|
parse: booleanSetting,
|
|
415
415
|
},
|
|
416
416
|
];
|
package/src/fast-controller.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { ResolvedConfig, ServiceTier, SupportedModel } from "./config.ts";
|
|
|
3
3
|
import { isRecord } from "./config.ts";
|
|
4
4
|
|
|
5
5
|
export const ULTRAFAST_NOTICE =
|
|
6
|
-
"Ultrafast uses 6x Standard token prices for API GPT-6 Astra (global/US only).
|
|
6
|
+
"Ultrafast uses 6x Standard token prices for API GPT-6 Astra (global/US only). ChatGPT subscription access (openai OAuth or legacy openai-codex) is not verified. Host cost estimates may exclude tier premiums.";
|
|
7
7
|
|
|
8
8
|
export function currentModelKey(ctx: ExtensionContext): string {
|
|
9
9
|
return ctx.model ? `${ctx.model.provider}/${ctx.model.id}` : "none";
|
|
@@ -22,7 +22,8 @@ export function supportsUltrafast(ctx: ExtensionContext): boolean {
|
|
|
22
22
|
if (
|
|
23
23
|
model?.provider !== "openai" ||
|
|
24
24
|
model.id !== "gpt-6-astra" ||
|
|
25
|
-
model.api !== "openai-responses"
|
|
25
|
+
model.api !== "openai-responses" ||
|
|
26
|
+
ctx.modelRegistry.isUsingOAuth(model)
|
|
26
27
|
)
|
|
27
28
|
return false;
|
|
28
29
|
try {
|
package/src/image.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { Box, Container, Image, Text } from "@earendil-works/pi-tui";
|
|
|
7
7
|
import sharp from "sharp";
|
|
8
8
|
import { isRecord, normalizeImageModel, type ResolvedConfig } from "./config.ts";
|
|
9
9
|
import {
|
|
10
|
+
CODEX_AUTH_REQUIRED,
|
|
10
11
|
extractAccountIdFromJwt,
|
|
11
12
|
getCodexCredentials,
|
|
12
13
|
type CodexCredentialsWithSource,
|
|
@@ -129,7 +130,7 @@ async function getCredentials(
|
|
|
129
130
|
): Promise<CodexImageCredentials> {
|
|
130
131
|
const credentials = await getCodexCredentials(ctx, signal);
|
|
131
132
|
if (credentials) return credentials;
|
|
132
|
-
throw new Error(
|
|
133
|
+
throw new Error(CODEX_AUTH_REQUIRED);
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
function resolveModel(params: Pick<ToolParams, "model">, cfg: ResolvedConfig): string {
|
package/src/live/transport.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { HttpsProxyAgent } from "https-proxy-agent";
|
|
|
2
2
|
import { getProxyForUrl } from "proxy-from-env";
|
|
3
3
|
import { fetch as undiciFetch, ProxyAgent } from "undici";
|
|
4
4
|
import WebSocket, { type RawData } from "ws";
|
|
5
|
-
import type
|
|
5
|
+
import { CODEX_AUTH_REQUIRED, type CodexCredentials } from "../codex-auth.ts";
|
|
6
6
|
import { generateCodexAttestation } from "./attestation.ts";
|
|
7
7
|
import { loadLiveNative, type LiveNativeBindings, type LiveWebRtcPeerInstance } from "./native.ts";
|
|
8
8
|
import {
|
|
@@ -186,7 +186,7 @@ export class CodexLiveTransport {
|
|
|
186
186
|
async #signal(offer: string): Promise<LiveSignalingResult> {
|
|
187
187
|
const credentials = await this.#options.getCredentials(this.#operationSignal);
|
|
188
188
|
if (!credentials) {
|
|
189
|
-
throw new Error(
|
|
189
|
+
throw new Error(CODEX_AUTH_REQUIRED);
|
|
190
190
|
}
|
|
191
191
|
const attestation = await generateCodexAttestation(this.#native);
|
|
192
192
|
const headers = buildLiveHeaders(
|
package/src/reset-controller.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { getCodexCredentials } from "./codex-auth.ts";
|
|
2
|
+
import { CODEX_AUTH_REQUIRED, getCodexCredentials } from "./codex-auth.ts";
|
|
3
3
|
import { sanitizeDiagnosticError } from "./format.ts";
|
|
4
4
|
import { reserveBankedResetRedemption } from "./reset-guard.ts";
|
|
5
5
|
import {
|
|
@@ -91,7 +91,7 @@ export class ResetController {
|
|
|
91
91
|
this.cache = { credits, updatedAt: Date.now() };
|
|
92
92
|
this.error = undefined;
|
|
93
93
|
} else {
|
|
94
|
-
this.error =
|
|
94
|
+
this.error = CODEX_AUTH_REQUIRED;
|
|
95
95
|
}
|
|
96
96
|
} catch (error) {
|
|
97
97
|
if (generation !== this.generation || signal.aborted) return;
|
|
@@ -130,7 +130,7 @@ export class ResetController {
|
|
|
130
130
|
const signal = this.requestSignal(ctx);
|
|
131
131
|
const credentials = await getCodexCredentials(ctx, signal);
|
|
132
132
|
signal.throwIfAborted();
|
|
133
|
-
if (!credentials) throw new Error(
|
|
133
|
+
if (!credentials) throw new Error(CODEX_AUTH_REQUIRED);
|
|
134
134
|
if (!reserveBankedResetRedemption(credentials.accountId, creditId))
|
|
135
135
|
throw new Error(
|
|
136
136
|
"A banked reset was already attempted recently; no additional credit was spent.",
|
|
@@ -159,7 +159,7 @@ export class ResetController {
|
|
|
159
159
|
);
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
private scheduleAutoRedeem(): void {
|
|
162
|
+
private scheduleAutoRedeem(scheduled?: BankedResetCredit): void {
|
|
163
163
|
const ctx = this.activeCtx;
|
|
164
164
|
if (!ctx || this.redeeming) return;
|
|
165
165
|
try {
|
|
@@ -170,7 +170,7 @@ export class ResetController {
|
|
|
170
170
|
// A cache refresh must not replace a due timer with the next credit,
|
|
171
171
|
// particularly when the scheduled one was redeemed in another client.
|
|
172
172
|
if (this.autoTimer) return;
|
|
173
|
-
const credit = selectAutoRedeemCredit(this.cache?.credits.credits ?? []);
|
|
173
|
+
const credit = scheduled ?? selectAutoRedeemCredit(this.cache?.credits.credits ?? []);
|
|
174
174
|
if (!credit || credit.expiresAtMs === null) return;
|
|
175
175
|
const dueAt = Math.max(
|
|
176
176
|
credit.expiresAtMs - BANKED_RESET_AUTO_REDEEM_LEAD_MS,
|
|
@@ -179,7 +179,9 @@ export class ResetController {
|
|
|
179
179
|
this.autoTimer = setTimeout(
|
|
180
180
|
() => {
|
|
181
181
|
this.autoTimer = undefined;
|
|
182
|
-
|
|
182
|
+
// Preserve the exact credit across capped timer wakeups, even when
|
|
183
|
+
// a polling refresh has changed the cached credit list.
|
|
184
|
+
if (Date.now() < dueAt) this.scheduleAutoRedeem(credit);
|
|
183
185
|
else void this.autoRedeem(ctx, credit);
|
|
184
186
|
},
|
|
185
187
|
Math.max(0, Math.min(dueAt - Date.now(), BANKED_RESET_CACHE_TTL_MS)),
|
package/src/resets.ts
CHANGED
|
@@ -7,11 +7,10 @@ export const RESET_CREDITS_URL = "https://chatgpt.com/backend-api/wham/rate-limi
|
|
|
7
7
|
export const CONSUME_RESET_URL =
|
|
8
8
|
"https://chatgpt.com/backend-api/wham/rate-limit-reset-credits/consume";
|
|
9
9
|
|
|
10
|
-
// Auto-redeem fires
|
|
11
|
-
// (credentials, a fresh credit re-check,
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
export const BANKED_RESET_AUTO_REDEEM_LEAD_MS = 60_000;
|
|
10
|
+
// Auto-redeem fires ten minutes before expiry to leave more headroom than a
|
|
11
|
+
// last-minute attempt. The automatic flow (credentials, a fresh credit re-check,
|
|
12
|
+
// reservation, and consume POST) still shares one 10s abort deadline.
|
|
13
|
+
export const BANKED_RESET_AUTO_REDEEM_LEAD_MS = 10 * 60_000;
|
|
15
14
|
|
|
16
15
|
export type BankedResetStatus = "available" | "redeeming" | "redeemed" | "unknown";
|
|
17
16
|
|
package/src/usage-controller.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
usageSegments,
|
|
15
15
|
} from "./usage.ts";
|
|
16
16
|
import { currentModelKey } from "./fast-controller.ts";
|
|
17
|
+
import { CODEX_AUTH_REQUIRED } from "./codex-auth.ts";
|
|
17
18
|
|
|
18
19
|
export function isOpenAISubscriptionModel(
|
|
19
20
|
ctx: ExtensionContext,
|
|
@@ -77,13 +78,19 @@ export class UsageController {
|
|
|
77
78
|
cfg = this.getConfig(ctx),
|
|
78
79
|
isUsingOAuth?: boolean,
|
|
79
80
|
): UsageSegment[] | undefined {
|
|
80
|
-
|
|
81
|
-
!this.
|
|
82
|
-
this.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
if (
|
|
82
|
+
!this.usageSnapshot ||
|
|
83
|
+
this.usageError ||
|
|
84
|
+
this.usageSnapshot.scope !== usageScopeForModel(ctx.model?.id) ||
|
|
85
|
+
!cfg.usage.enabled ||
|
|
86
|
+
!isOpenAISubscriptionModel(ctx, cfg, isUsingOAuth)
|
|
87
|
+
)
|
|
88
|
+
return undefined;
|
|
89
|
+
const segments = usageSegments(this.usageSnapshot, cfg.usage);
|
|
90
|
+
// The new OpenAI subscription login and the Codex backend login are independent.
|
|
91
|
+
// Never present a separately authenticated Codex account as the active OpenAI quota.
|
|
92
|
+
if (ctx.model?.provider === "openai") segments.unshift({ text: "Codex ", severity: "muted" });
|
|
93
|
+
return segments;
|
|
87
94
|
}
|
|
88
95
|
|
|
89
96
|
statusLine(
|
|
@@ -108,7 +115,11 @@ export class UsageController {
|
|
|
108
115
|
this.usageUpdatedAt && Date.now() - this.usageUpdatedAt > cfg.usage.refreshIntervalMs * 2
|
|
109
116
|
? ` · stale ${formatResetCountdown((Date.now() - this.usageUpdatedAt) / 1000)}`
|
|
110
117
|
: "";
|
|
111
|
-
|
|
118
|
+
const source =
|
|
119
|
+
ctx.model?.provider === "openai"
|
|
120
|
+
? "Codex account (not verified against the active OpenAI login; OpenAI usage: https://chatgpt.com/settings/usage). "
|
|
121
|
+
: "";
|
|
122
|
+
return `${source}${formatUsageSnapshot(this.usageSnapshot, cfg.usage)}${stale}`;
|
|
112
123
|
}
|
|
113
124
|
|
|
114
125
|
formatDebug(ctx: ExtensionContext): string {
|
|
@@ -119,6 +130,7 @@ export class UsageController {
|
|
|
119
130
|
`Current model: ${currentModelKey(ctx)}`,
|
|
120
131
|
`Current model eligible: ${isOpenAISubscriptionModel(ctx, cfg)}`,
|
|
121
132
|
`Requires subscription model: ${cfg.usage.showOnlyOnSubscriptionModels}`,
|
|
133
|
+
"Credential provider: openai-codex (independent of /login openai)",
|
|
122
134
|
`Auth: ${auth ? "found" : "missing"}`,
|
|
123
135
|
`Account ID: ${maskIdentifier(auth?.accountId) ?? "none"}`,
|
|
124
136
|
`Last fetch: ${this.usageLastFetchAt ? new Date(this.usageLastFetchAt).toLocaleTimeString() : "never"}`,
|
|
@@ -214,9 +226,7 @@ export class UsageController {
|
|
|
214
226
|
|
|
215
227
|
this.usageSnapshot = data ? parseUsageSnapshot(data, resolvedModelId) : undefined;
|
|
216
228
|
this.usageUpdatedAt = this.usageSnapshot ? Date.now() : undefined;
|
|
217
|
-
this.usageError = data
|
|
218
|
-
? undefined
|
|
219
|
-
: `Missing openai-codex OAuth credentials in ${AUTH_FILE}.`;
|
|
229
|
+
this.usageError = data ? undefined : `${CODEX_AUTH_REQUIRED} Auth store: ${AUTH_FILE}.`;
|
|
220
230
|
this.updateFooter(ctx);
|
|
221
231
|
if (options?.notify)
|
|
222
232
|
ctx.ui.notify(this.formatStatus(ctx), this.usageSnapshot ? "info" : "warning");
|
package/src/websearch.ts
CHANGED
|
@@ -6,7 +6,11 @@ import {
|
|
|
6
6
|
type ResolvedConfig,
|
|
7
7
|
type WebsearchResponseLength,
|
|
8
8
|
} from "./config.ts";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
CODEX_AUTH_REQUIRED,
|
|
11
|
+
getCodexCredentials,
|
|
12
|
+
type CodexCredentialsWithSource,
|
|
13
|
+
} from "./codex-auth.ts";
|
|
10
14
|
import { maskIdentifier, sanitizeDiagnosticError } from "./format.ts";
|
|
11
15
|
import { registerOptionalTool, type OptionalTool } from "./optional-tool.ts";
|
|
12
16
|
|
|
@@ -90,10 +94,7 @@ async function getCredentials(
|
|
|
90
94
|
): Promise<CodexCredentialsWithSource> {
|
|
91
95
|
const credentials = await getCodexCredentials(ctx, signal);
|
|
92
96
|
if (credentials) return credentials;
|
|
93
|
-
throw new WebSearchError(
|
|
94
|
-
"authentication_required",
|
|
95
|
-
"Missing openai-codex OAuth credentials. Run /login openai-codex.",
|
|
96
|
-
);
|
|
97
|
+
throw new WebSearchError("authentication_required", CODEX_AUTH_REQUIRED);
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
export function validateSearchQuery(query: string): string {
|