@monotykamary/pi-better-openai 0.1.34 → 0.1.36

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
@@ -29,6 +29,7 @@ Usage display, image generation, and live voice require pi's `openai-codex` OAut
29
29
 
30
30
  ## Features
31
31
 
32
+ - GPT-6 Astra and Daybreak Blue/Red model fallbacks for the built-in `openai-codex` provider.
32
33
  - Fast mode for supported OpenAI models, toggled with `/fast` or in `/openai-settings`.
33
34
  - OpenAI subscription usage display via `/openai-usage` and the footer.
34
35
  - Interactive settings picker via `/openai-settings`.
@@ -61,6 +62,7 @@ Default supported models:
61
62
  [
62
63
  "openai/gpt-5.4",
63
64
  "openai/gpt-5.5",
65
+ "openai-codex/gpt-6-astra",
64
66
  "openai-codex/gpt-5.6-sol",
65
67
  "openai-codex/gpt-5.6-terra",
66
68
  "openai-codex/gpt-5.6-luna",
@@ -111,6 +113,12 @@ Example config:
111
113
  }
112
114
  ```
113
115
 
116
+ ## Codex model fallbacks
117
+
118
+ The extension adds `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.
119
+
120
+ Daybreak models require separate OpenAI approval and provisioning. pi currently exposes reasoning levels through `max`; Codex's `ultra` automatic-delegation mode is not a pi thinking level.
121
+
114
122
  ## Live voice
115
123
 
116
124
  Run `/live` or press `Ctrl+Shift+L` to open the realtime voice panel. `Ctrl+L` remains pi's model selector, so the extension deliberately uses the shifted chord. While live mode has focus:
package/index.ts CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  SettingsList,
13
13
  type SettingsListTheme,
14
14
  } from "@earendil-works/pi-tui";
15
+ import { registerOpenAICodexModels } from "./src/codex-models.ts";
15
16
  import { CONFIG_BASENAME, STATUS_KEY } from "./src/identity.ts";
16
17
  import {
17
18
  formatTokens,
@@ -209,6 +210,8 @@ function textPanel(title: string, lines: string[], done: () => void) {
209
210
  }
210
211
 
211
212
  export default function betterOpenAI(pi: ExtensionAPI): void {
213
+ registerOpenAICodexModels(pi);
214
+
212
215
  const fastController = new FastController(SERVICE_TIER);
213
216
  let cachedConfig: ResolvedConfig | undefined;
214
217
  let footerTotals = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monotykamary/pi-better-openai",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
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",
@@ -62,8 +62,9 @@
62
62
  "ws": "8.21.2"
63
63
  },
64
64
  "devDependencies": {
65
- "@earendil-works/pi-coding-agent": "0.84.4",
66
- "@earendil-works/pi-tui": "0.84.4",
65
+ "@earendil-works/pi-ai": "0.85.0",
66
+ "@earendil-works/pi-coding-agent": "0.85.0",
67
+ "@earendil-works/pi-tui": "0.85.0",
67
68
  "@types/node": "~22.19.0",
68
69
  "@types/proxy-from-env": "1.0.4",
69
70
  "@types/ws": "8.18.1",
@@ -73,6 +74,7 @@
73
74
  "vitest": "^4.1.5"
74
75
  },
75
76
  "peerDependencies": {
77
+ "@earendil-works/pi-ai": "*",
76
78
  "@earendil-works/pi-coding-agent": "*",
77
79
  "@earendil-works/pi-tui": "*"
78
80
  },
@@ -84,8 +86,8 @@
84
86
  "@oh-my-pi/pi-natives-win32-x64": "17.2.9"
85
87
  },
86
88
  "overrides": {
87
- "@earendil-works/pi-agent-core": "0.84.4",
88
- "@earendil-works/pi-ai": "0.84.4",
89
+ "@earendil-works/pi-agent-core": "0.85.0",
90
+ "@earendil-works/pi-ai": "0.85.0",
89
91
  "brace-expansion": "5.0.9",
90
92
  "nanoid": "3.3.18",
91
93
  "postcss": "8.5.25",
@@ -0,0 +1,203 @@
1
+ import {
2
+ createProvider,
3
+ type Model,
4
+ type Provider,
5
+ type RefreshModelsContext,
6
+ } from "@earendil-works/pi-ai";
7
+ import { openAICodexResponsesApi } from "@earendil-works/pi-ai/api/openai-codex-responses.lazy";
8
+ import { openaiCodexProvider } from "@earendil-works/pi-ai/providers/openai-codex";
9
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
10
+
11
+ const CODEX_API = "openai-codex-responses" as const;
12
+ const CODEX_BASE_URL = "https://chatgpt.com/backend-api";
13
+ const CODEX_CATALOG_URL = "https://pi.dev/api/models/providers/openai-codex";
14
+ const CODEX_PROVIDER_ID = "openai-codex";
15
+ const CATALOG_REFRESH_INTERVAL_MS = 4 * 60 * 60 * 1000;
16
+
17
+ type CodexModel = Model<typeof CODEX_API>;
18
+
19
+ type CreateCodexProviderOptions = {
20
+ fetch?: typeof globalThis.fetch;
21
+ now?: () => number;
22
+ };
23
+
24
+ const CODEX_COMPAT = {
25
+ supportsOpenAIGrammarTools: true,
26
+ supportsAdditionalTools: true,
27
+ supportsToolSearch: true,
28
+ } as const;
29
+
30
+ export const CODEX_MODEL_FALLBACKS: CodexModel[] = [
31
+ {
32
+ id: "gpt-6-astra",
33
+ name: "GPT-6 Astra",
34
+ api: CODEX_API,
35
+ provider: CODEX_PROVIDER_ID,
36
+ baseUrl: CODEX_BASE_URL,
37
+ reasoning: true,
38
+ thinkingLevelMap: {
39
+ minimal: "low",
40
+ xhigh: "xhigh",
41
+ max: "max",
42
+ },
43
+ input: ["text", "image"],
44
+ contextWindow: 272000,
45
+ maxTokens: 128000,
46
+ cost: {
47
+ input: 10,
48
+ output: 50,
49
+ cacheRead: 1,
50
+ cacheWrite: 12.5,
51
+ tiers: [
52
+ {
53
+ inputTokensAbove: 272000,
54
+ input: 20,
55
+ output: 75,
56
+ cacheRead: 2,
57
+ cacheWrite: 25,
58
+ },
59
+ ],
60
+ },
61
+ compat: CODEX_COMPAT,
62
+ },
63
+ {
64
+ id: "gpt-daybreak-blue-latest",
65
+ name: "Daybreak Blue",
66
+ api: CODEX_API,
67
+ provider: CODEX_PROVIDER_ID,
68
+ baseUrl: CODEX_BASE_URL,
69
+ reasoning: true,
70
+ thinkingLevelMap: {
71
+ minimal: "low",
72
+ xhigh: "xhigh",
73
+ max: "max",
74
+ },
75
+ input: ["text", "image"],
76
+ contextWindow: 272000,
77
+ maxTokens: 128000,
78
+ cost: {
79
+ input: 4,
80
+ output: 20,
81
+ cacheRead: 0.4,
82
+ cacheWrite: 5,
83
+ tiers: [
84
+ {
85
+ inputTokensAbove: 272000,
86
+ input: 8,
87
+ output: 30,
88
+ cacheRead: 0.8,
89
+ cacheWrite: 10,
90
+ },
91
+ ],
92
+ },
93
+ compat: CODEX_COMPAT,
94
+ },
95
+ {
96
+ id: "gpt-daybreak-red-latest",
97
+ name: "Daybreak Red",
98
+ api: CODEX_API,
99
+ provider: CODEX_PROVIDER_ID,
100
+ baseUrl: CODEX_BASE_URL,
101
+ reasoning: true,
102
+ thinkingLevelMap: {
103
+ minimal: "low",
104
+ xhigh: "xhigh",
105
+ max: "max",
106
+ },
107
+ input: ["text", "image"],
108
+ contextWindow: 372000,
109
+ maxTokens: 128000,
110
+ cost: {
111
+ input: 12.5,
112
+ output: 75,
113
+ cacheRead: 1.25,
114
+ cacheWrite: 15.625,
115
+ },
116
+ compat: CODEX_COMPAT,
117
+ },
118
+ ];
119
+
120
+ function isRecord(value: unknown): value is Record<string, unknown> {
121
+ return typeof value === "object" && value !== null && !Array.isArray(value);
122
+ }
123
+
124
+ function catalogEntries(value: unknown): unknown[] | undefined {
125
+ if (Array.isArray(value)) return value;
126
+ if (!isRecord(value)) return undefined;
127
+ if (Array.isArray(value.models)) return value.models;
128
+ return Object.values(value);
129
+ }
130
+
131
+ export function parseCodexCatalog(value: unknown): CodexModel[] {
132
+ const entries = catalogEntries(value);
133
+ if (!entries) throw new Error("Invalid openai-codex model catalog");
134
+
135
+ return entries
136
+ .filter((entry): entry is Record<string, unknown> => {
137
+ return isRecord(entry) && typeof entry.id === "string" && entry.id.length > 0;
138
+ })
139
+ .map((entry) => ({ ...entry, provider: CODEX_PROVIDER_ID }) as CodexModel);
140
+ }
141
+
142
+ export function appendMissingCodexModels(
143
+ models: readonly CodexModel[],
144
+ fallbacks: readonly CodexModel[] = CODEX_MODEL_FALLBACKS,
145
+ ): CodexModel[] {
146
+ const merged = [...models];
147
+ const modelIds = new Set(merged.map((model) => model.id));
148
+ for (const model of fallbacks) {
149
+ if (modelIds.has(model.id)) continue;
150
+ merged.push(model);
151
+ modelIds.add(model.id);
152
+ }
153
+ return merged;
154
+ }
155
+
156
+ function storedCodexModels(context: RefreshModelsContext): CodexModel[] {
157
+ return (context.stored?.models ?? []).filter(
158
+ (model): model is CodexModel => model.provider === CODEX_PROVIDER_ID && model.api === CODEX_API,
159
+ );
160
+ }
161
+
162
+ async function fetchCodexModels(
163
+ context: RefreshModelsContext,
164
+ options: CreateCodexProviderOptions,
165
+ ): Promise<readonly CodexModel[]> {
166
+ const cached = storedCodexModels(context);
167
+ const checkedAt = context.stored?.checkedAt;
168
+ const now = options.now?.() ?? Date.now();
169
+ if (!context.force && checkedAt !== undefined && now - checkedAt < CATALOG_REFRESH_INTERVAL_MS) {
170
+ return cached;
171
+ }
172
+
173
+ const response = await (options.fetch ?? globalThis.fetch)(CODEX_CATALOG_URL, {
174
+ headers: { accept: "application/json" },
175
+ signal: context.signal,
176
+ });
177
+ if (response.status === 404 || response.status === 501) return cached;
178
+ if (!response.ok) {
179
+ throw new Error(`OpenAI Codex model catalog request failed: ${response.status}`);
180
+ }
181
+ return parseCodexCatalog(await response.json());
182
+ }
183
+
184
+ export function createOpenAICodexProvider(
185
+ options: CreateCodexProviderOptions = {},
186
+ ): Provider<typeof CODEX_API> {
187
+ const builtIn = openaiCodexProvider();
188
+ return createProvider({
189
+ id: builtIn.id,
190
+ name: builtIn.name,
191
+ baseUrl: builtIn.baseUrl,
192
+ headers: builtIn.headers,
193
+ auth: builtIn.auth,
194
+ models: appendMissingCodexModels(builtIn.getModels()),
195
+ fetchModels: (context) => fetchCodexModels(context, options),
196
+ filterModels: builtIn.filterModels,
197
+ api: openAICodexResponsesApi(),
198
+ });
199
+ }
200
+
201
+ export function registerOpenAICodexModels(pi: ExtensionAPI): void {
202
+ pi.registerProvider(createOpenAICodexProvider());
203
+ }
package/src/config.ts CHANGED
@@ -37,6 +37,7 @@ export const PET_STATES = [
37
37
  export const DEFAULT_SUPPORTED_MODELS = [
38
38
  "openai/gpt-5.4",
39
39
  "openai/gpt-5.5",
40
+ "openai-codex/gpt-6-astra",
40
41
  "openai-codex/gpt-5.6-sol",
41
42
  "openai-codex/gpt-5.6-terra",
42
43
  "openai-codex/gpt-5.6-luna",