@monotykamary/pi-better-openai 0.2.11 → 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 +8 -0
- package/README.md +9 -5
- package/package.json +6 -6
- package/src/codex-auth.ts +5 -0
- 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 +3 -3
- package/src/usage-controller.ts +21 -11
- package/src/websearch.ts +6 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
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
|
+
|
|
3
11
|
## 0.2.11
|
|
4
12
|
|
|
5
13
|
- Auto-redeem banked Codex resets ten minutes before expiry instead of one minute, with matching settings and redemption-time displays.
|
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
|
|
|
@@ -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/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.",
|
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 {
|