@monotykamary/pi-better-openai 0.2.6 → 0.2.8

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 ADDED
@@ -0,0 +1,14 @@
1
+ # Changelog
2
+
3
+ ## 0.2.8
4
+
5
+ - Add GPT-6.1 Sol fallback metadata and Fast support for the GPT-6 model family.
6
+ - Add `/openai-tier` for Standard, Fast, and capability-gated API Astra Ultrafast, with explicit pricing warnings, persistence, diagnostics, and footer labels.
7
+ - Add opt-in `openai_decide` and `/openai-decisions` through Pi's classifier API, with typed validation, cancellation, safe errors, and usage accounting.
8
+ - Include classifier tool usage in footer totals and preserve legacy Fast settings and customized model lists.
9
+ - Document remaining native OpenAI Decisions, Codex subscription Ultrafast, and hosted multi-agent integration gates; no undocumented endpoint or chat fallback is assumed.
10
+
11
+ ## 0.2.7
12
+
13
+ - Validate against Pi 0.99.0, including an offline real-host package-loading probe.
14
+ - Declare imported host packages as wildcard peers and pin development dependencies to Pi 0.99.0.
package/README.md CHANGED
@@ -30,8 +30,9 @@ Usage display, image generation, and live voice require pi's `openai-codex` OAut
30
30
 
31
31
  ## Features
32
32
 
33
- - GPT-6 Astra and Daybreak Blue/Red model fallbacks for the built-in `openai-codex` provider.
34
- - Fast mode for supported OpenAI models, toggled with `/fast` or in `/openai-settings`.
33
+ - GPT-6.1 Sol, GPT-6 Astra, and Daybreak Blue/Red model fallbacks for the built-in `openai-codex` provider.
34
+ - Standard, Fast, and capability-gated Ultrafast service tiers via `/openai-tier` or `/openai-settings`; `/fast` remains a quick Fast toggle.
35
+ - Opt-in typed decisions through `openai_decide`, using an explicitly selected Pi classifier provider (including Jev). Native OpenAI Decisions remains gated on a published adapter.
35
36
  - OpenAI subscription usage display via `/openai-usage` and the footer.
36
37
  - Interactive settings picker via `/openai-settings`.
37
38
  - Footer customization for model, thinking, fast mode, usage, and token/cost context.
@@ -40,7 +41,9 @@ Usage display, image generation, and live voice require pi's `openai-codex` OAut
40
41
  - Codex-backed realtime voice through `/live`, with an animated microphone waveform and coding-task delegation into the active pi session.
41
42
  - Animated Codex custom pets rendered in the Better OpenAI footer.
42
43
  - Commands:
43
- - `/fast` toggles fast mode.
44
+ - `/fast` toggles Fast and Standard; it never enables Ultrafast.
45
+ - `/openai-tier [standard|fast|ultrafast]` shows or selects the requested service tier.
46
+ - `/openai-decisions [models|use provider/model|off]` inspects or configures typed decisions.
44
47
  - `/openai-image <prompt>` generates an image directly.
45
48
  - `/openai-websearch <query>` searches the web and inserts the cited answer into the session.
46
49
  - `/live` starts or stops realtime voice mode. `Ctrl+Shift+L` is the keyboard toggle.
@@ -72,7 +75,14 @@ Default supported models:
72
75
  [
73
76
  "openai/gpt-5.4",
74
77
  "openai/gpt-5.5",
78
+ "openai/gpt-6-astra",
79
+ "openai/gpt-6.1-sol",
80
+ "openai/gpt-6-sol",
81
+ "openai/gpt-6-luna",
75
82
  "openai-codex/gpt-6-astra",
83
+ "openai-codex/gpt-6.1-sol",
84
+ "openai-codex/gpt-6-sol",
85
+ "openai-codex/gpt-6-luna",
76
86
  "openai-codex/gpt-5.6-sol",
77
87
  "openai-codex/gpt-5.6-terra",
78
88
  "openai-codex/gpt-5.6-luna",
@@ -87,8 +97,12 @@ Example config:
87
97
  {
88
98
  "persistState": true,
89
99
  "notifyOnModelSwitch": true,
90
- "desiredActive": false,
91
- "supportedModels": ["openai/gpt-5.5", "openai-codex/gpt-5.5"],
100
+ "serviceTier": "standard",
101
+ "decisions": {
102
+ "enabled": false,
103
+ "model": "",
104
+ "timeoutMs": 10000
105
+ },
92
106
  "usage": {
93
107
  "enabled": true,
94
108
  "refreshIntervalMs": 60000,
@@ -125,9 +139,56 @@ Example config:
125
139
  }
126
140
  ```
127
141
 
142
+ ## Service tiers
143
+
144
+ `/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.
145
+
146
+ `/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 Codex subscription Ultrafast 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.
147
+
148
+ 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).
149
+
150
+ `serviceTier` takes precedence over legacy `desiredActive`/`active` within each config layer; project state still overrides global state. `persistState: false` keeps tier changes session-only. `supportedModels` overrides the Fast allowlist, not Ultrafast capabilities. Unknown config fields and customized model lists are preserved.
151
+
152
+ ## Typed decisions
153
+
154
+ The `openai_decide` tool returns typed judgments through Pi's classifier API, **not chat completions**. It is disabled by default and never chooses a provider automatically. To use an existing Jev classifier explicitly:
155
+
156
+ ```text
157
+ /openai-decisions models
158
+ /openai-decisions use typesafe/jev-latest
159
+ ```
160
+
161
+ Configure that provider's credentials through Pi (for example, `TYPESAFE_API_KEY` for TypeSafe). The model list shows registered classifiers, not guaranteed credentials or entitlement. `/openai-decisions use` saves the selected model and enables decisions in the active project/global config; `/openai-decisions off` disables requests. These settings are independent of service-tier persistence. Provider-qualified IDs containing further slashes, such as `openrouter/typesafe/jev-1.13`, are supported when registered by the host. Prefer pinned versions for stable evaluations.
162
+
163
+ **Native OpenAI Decisions is not yet implemented:** as of the September 29, 2026 research checkpoint, no verifiable public endpoint/schema or SDK adapter was found. The bridge accepts OpenAI only once a classifier adapter is registered in Pi; it does not invent an endpoint, forward Codex OAuth to another service, or silently substitute a chat model. See the [integration status and remaining gates](plans/devday-integration.md).
164
+
165
+ Example tool input:
166
+
167
+ ```json
168
+ {
169
+ "state": { "testFailure": "connection to local test database timed out" },
170
+ "questions": {
171
+ "route": {
172
+ "type": "choice",
173
+ "instructions": "Classify the failure for human review.",
174
+ "criteria": { "environment": "Environment problem", "code": "Code defect" }
175
+ }
176
+ }
177
+ }
178
+ ```
179
+
180
+ - `state`: JSON object; send only the necessary context, never credentials or the entire session.
181
+ - `questions`: 1–32 named questions. `choice` uses 2–64 labeled criteria; `bool` uses `true`/`false` criteria; `score` uses 2–64 ordered criteria. Pi maps boolean questions to Jev's `noul` representation.
182
+ - Total input is capped at 64 KiB. `decisions.timeoutMs` defaults to 10000 and is clamped to 1000–60000. Cancellation/deadlines abort the provider request; there are no automatic retries. A timed-out upstream request may still incur charges.
183
+ - Results have `status: "ok"`, provider/model provenance, and typed `answers`; errors have `status: "error"` and mark the tool failed. Structured output is available to programmatic callers. Provider error text is withheld to prevent credential/state leakage.
184
+ - Probabilities and confidence remain uncertain judgments; scores retain their provider-specific scale. No claim of cross-provider calibration is made. Decisions never authorize tools, execute commands, change the active model, or start background polling.
185
+ - Reported classifier token usage/cost is included in tool results and the Better OpenAI footer. Missing usage or catalog pricing is not evidence that a request was free.
186
+
128
187
  ## Codex model fallbacks
129
188
 
130
- 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.
189
+ 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.
190
+
191
+ 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).
131
192
 
132
193
  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.
133
194
 
package/index.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  /**
2
2
  * Better OpenAI for pi.
3
3
  *
4
- * Adds `service_tier: "priority"` to OpenAI provider payloads while fast mode is
5
- * enabled and the selected model is in the configured allow-list.
4
+ * Adds capability-gated OpenAI service tiers and opt-in native typed decisions.
6
5
  */
7
6
  import {
8
7
  type ExtensionAPI,
@@ -17,6 +16,7 @@ import {
17
16
  SettingsList,
18
17
  type SettingsListTheme,
19
18
  } from "@earendil-works/pi-tui";
19
+ import type { Usage } from "@earendil-works/pi-ai";
20
20
  import { registerOpenAICodexModels } from "./src/codex-models.ts";
21
21
  import { CONFIG_BASENAME, STATUS_KEY } from "./src/identity.ts";
22
22
  import {
@@ -49,6 +49,8 @@ import {
49
49
  LIVE_SETTING_DESCRIPTORS,
50
50
  PET_SETTING_DESCRIPTORS,
51
51
  FAST_SETTING_DESCRIPTORS,
52
+ DECISIONS_SETTING_DESCRIPTORS,
53
+ isServiceTier,
52
54
  type SettingsOptionDescriptor,
53
55
  configPaths,
54
56
  type ResolvedConfig,
@@ -80,6 +82,7 @@ import { ResetController } from "./src/reset-controller.ts";
80
82
  import { registerOpenAIImage, _imageTest } from "./src/image.ts";
81
83
  import { registerOpenAIWebSearch, _websearchTest } from "./src/websearch.ts";
82
84
  import { registerOpenAILive } from "./src/live/index.ts";
85
+ import { registerOpenAIDecisions } from "./src/decisions.ts";
83
86
  import {
84
87
  type CodexPetPackage,
85
88
  codexHome,
@@ -91,7 +94,7 @@ import {
91
94
  registerOpenAIPets,
92
95
  _petsTest,
93
96
  } from "./src/pets.ts";
94
- import { FastController, modelList, supportsFast } from "./src/fast-controller.ts";
97
+ import { FastController, supportsFast } from "./src/fast-controller.ts";
95
98
  import { isOpenAISubscriptionModel, UsageController } from "./src/usage-controller.ts";
96
99
  import { PetFooterController } from "./src/pet-footer-controller.ts";
97
100
  import {
@@ -338,12 +341,14 @@ export default function betterOpenAI(pi: ExtensionAPI): void {
338
341
  ...nextConfig,
339
342
  active: fastController.active,
340
343
  desiredActive: fastController.desiredActive,
344
+ serviceTier: fastController.desiredTier,
341
345
  };
342
346
  if (!nextConfig.persistState) return;
343
347
  writeConfig(nextConfig.configPath, {
344
348
  ...readRawConfig(nextConfig.configPath),
345
349
  active: fastController.active,
346
350
  desiredActive: fastController.desiredActive,
351
+ serviceTier: fastController.desiredTier,
347
352
  });
348
353
  }
349
354
 
@@ -368,15 +373,22 @@ export default function betterOpenAI(pi: ExtensionAPI): void {
368
373
  ctx.ui.notify(fastController.stateText(ctx, nextConfig), "info");
369
374
  }
370
375
 
376
+ function addFooterUsage(usage: Usage | undefined): void {
377
+ if (!usage) return;
378
+ footerTotals.input += usage.input;
379
+ footerTotals.output += usage.output;
380
+ footerTotals.cacheRead += usage.cacheRead;
381
+ footerTotals.cacheWrite += usage.cacheWrite;
382
+ footerTotals.cost += usage.cost.total;
383
+ }
384
+
371
385
  function refreshFooterTotals(ctx: ExtensionContext): void {
372
386
  footerTotals = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 };
373
387
  for (const entry of ctx.sessionManager.getEntries()) {
374
- if (entry.type !== "message" || entry.message.role !== "assistant") continue;
375
- footerTotals.input += entry.message.usage.input;
376
- footerTotals.output += entry.message.usage.output;
377
- footerTotals.cacheRead += entry.message.usage.cacheRead;
378
- footerTotals.cacheWrite += entry.message.usage.cacheWrite;
379
- footerTotals.cost += entry.message.usage.cost.total;
388
+ if (entry.type !== "message") continue;
389
+ if (entry.message.role === "assistant" || entry.message.role === "toolResult") {
390
+ addFooterUsage(entry.message.usage);
391
+ }
380
392
  }
381
393
  }
382
394
 
@@ -433,6 +445,9 @@ export default function betterOpenAI(pi: ExtensionAPI): void {
433
445
  `Image default save: ${cfg.image.defaultSave}`,
434
446
  `Websearch enabled: ${cfg.websearch.enabled}`,
435
447
  `Websearch model: ${cfg.websearch.model} (${cfg.websearch.reasoningEffort}/${cfg.websearch.responseLength}, ${cfg.websearch.maxOutputTokens} tokens, ${cfg.websearch.timeoutMs}ms)`,
448
+ `Decisions enabled: ${cfg.decisions.enabled}`,
449
+ `Decision classifier: ${cfg.decisions.model || "not selected"} (${cfg.decisions.timeoutMs}ms)`,
450
+ "Native OpenAI Decisions requires a registered classifier adapter; no chat fallback.",
436
451
  `Live enabled: ${cfg.live.enabled}`,
437
452
  `Live voice: ${cfg.live.voice}`,
438
453
  `Pet enabled: ${cfg.pets.enabled}`,
@@ -531,6 +546,37 @@ export default function betterOpenAI(pi: ExtensionAPI): void {
531
546
  },
532
547
  });
533
548
 
549
+ pi.registerCommand("openai-tier", {
550
+ description: "Select standard, fast, or ultrafast (API Astra; 6x Standard token prices)",
551
+ handler: async (args, ctx) => {
552
+ const tier = args.trim().toLowerCase();
553
+ if (!tier) {
554
+ ctx.ui.notify(
555
+ `Requested tier: ${fastController.desiredTier}. ${fastController.stateText(ctx, config(ctx))}`,
556
+ "info",
557
+ );
558
+ return;
559
+ }
560
+ if (!isServiceTier(tier)) {
561
+ ctx.ui.notify(
562
+ "Usage: /openai-tier [standard | fast | ultrafast]. Ultrafast explicitly opts into 6x Standard token prices.",
563
+ "error",
564
+ );
565
+ return;
566
+ }
567
+ const cfg = refresh(ctx);
568
+ fastController.setTier(ctx, cfg, tier);
569
+ persist(cfg);
570
+ updateFooter(ctx);
571
+ ctx.ui.notify(
572
+ fastController.stateText(ctx, cfg),
573
+ tier === "ultrafast" || (fastController.desiredActive && !fastController.active)
574
+ ? "warning"
575
+ : "info",
576
+ );
577
+ },
578
+ });
579
+
534
580
  pi.registerCommand(OPENAI_STATUS_COMMAND, {
535
581
  description: "Show OpenAI subscription usage status",
536
582
  handler: async (_args, ctx) => {
@@ -798,16 +844,9 @@ export default function betterOpenAI(pi: ExtensionAPI): void {
798
844
  }
799
845
 
800
846
  function buildFastSettingsItems(cfg: ResolvedConfig): SettingsPickerItem[] {
801
- return [
802
- {
803
- id: "fast.enabled",
804
- label: "Fast mode",
805
- currentValue: String(fastController.desiredActive),
806
- values: ["true", "false"],
807
- description: `Request OpenAI fast mode. Activates for supported models: ${modelList(cfg.supportedModels)}.`,
808
- },
809
- ...settingsItemsFromDescriptors(FAST_SETTING_DESCRIPTORS, cfg),
810
- ];
847
+ return settingsItemsFromDescriptors(FAST_SETTING_DESCRIPTORS, cfg, {
848
+ serviceTier: { currentValue: fastController.desiredTier },
849
+ });
811
850
  }
812
851
 
813
852
  function buildFooterSettingsItems(cfg: ResolvedConfig): SettingsPickerItem[] {
@@ -870,12 +909,13 @@ export default function betterOpenAI(pi: ExtensionAPI): void {
870
909
  return [
871
910
  {
872
911
  id: "section.fast",
873
- label: "Fast mode",
912
+ label: "Service tier",
874
913
  currentValue: fastSettingsSummary(ctx, cfg),
875
- description: "Configure OpenAI fast mode and persistence.",
914
+ description:
915
+ "Configure Standard, Fast, Ultrafast, and persistence. Ultrafast costs 6x Standard.",
876
916
  submenu: (_value, done) =>
877
917
  settingsSubmenu(
878
- "Fast mode settings",
918
+ "Service tier settings",
879
919
  () => buildFastSettingsItems(config(ctx)),
880
920
  ctx,
881
921
  () => done(fastSettingsSummary(ctx, config(ctx))),
@@ -933,6 +973,38 @@ export default function betterOpenAI(pi: ExtensionAPI): void {
933
973
  () => done(websearchSettingsSummary(config(ctx))),
934
974
  ),
935
975
  },
976
+ {
977
+ id: "section.decisions",
978
+ label: "Typed decisions",
979
+ currentValue: cfg.decisions.enabled ? cfg.decisions.model || "model required" : "disabled",
980
+ description: "Opt-in native classifier requests; no chat fallback or automatic actions.",
981
+ submenu: (_value, done) =>
982
+ settingsSubmenu(
983
+ "Typed decision settings",
984
+ () => {
985
+ const next = config(ctx);
986
+ const models = ctx.modelRegistry.getModelsOfType("classifier");
987
+ return settingsItemsFromDescriptors(DECISIONS_SETTING_DESCRIPTORS, next, {
988
+ "decisions.model": {
989
+ values: [
990
+ ...new Set([
991
+ "",
992
+ next.decisions.model,
993
+ ...models.map((model) => `${model.provider}/${model.id}`),
994
+ ]),
995
+ ],
996
+ },
997
+ });
998
+ },
999
+ ctx,
1000
+ () =>
1001
+ done(
1002
+ config(ctx).decisions.enabled
1003
+ ? config(ctx).decisions.model || "model required"
1004
+ : "disabled",
1005
+ ),
1006
+ ),
1007
+ },
936
1008
  {
937
1009
  id: "section.live",
938
1010
  label: "Live voice",
@@ -998,14 +1070,29 @@ export default function betterOpenAI(pi: ExtensionAPI): void {
998
1070
  const bool = rawValue === "true";
999
1071
  if (id === "fast.enabled") {
1000
1072
  fastController.setDesired(ctx, cfg, bool);
1073
+ } else if (id === "serviceTier") {
1074
+ if (!isServiceTier(rawValue)) return;
1075
+ fastController.setTier(ctx, cfg, rawValue);
1076
+ ctx.ui.notify(
1077
+ fastController.stateText(ctx, cfg),
1078
+ rawValue === "ultrafast" || (fastController.desiredActive && !fastController.active)
1079
+ ? "warning"
1080
+ : "info",
1081
+ );
1001
1082
  }
1002
1083
  const petKey = id.startsWith("pets.") ? id.slice("pets.".length) : undefined;
1003
1084
  const nextRawConfig = applySettingToRawConfig(current, id, rawValue, {
1004
1085
  persistState: cfg.persistState,
1005
1086
  active: fastController.active,
1006
1087
  desiredActive: fastController.desiredActive,
1088
+ serviceTier: fastController.desiredTier,
1007
1089
  petEmptyValue: PET_EMPTY_VALUE,
1008
1090
  });
1091
+ if (id === "persistState" && bool) {
1092
+ nextRawConfig.serviceTier = fastController.desiredTier;
1093
+ nextRawConfig.active = fastController.active;
1094
+ nextRawConfig.desiredActive = fastController.desiredActive;
1095
+ }
1009
1096
  if (petKey) {
1010
1097
  if (petKey === "enabled" || petKey === "sizeCells" || petKey === "slug")
1011
1098
  petController.invalidateLoadKey();
@@ -1102,6 +1189,7 @@ export default function betterOpenAI(pi: ExtensionAPI): void {
1102
1189
 
1103
1190
  registerOpenAIImage(pi, config);
1104
1191
  registerOpenAIWebSearch(pi, config);
1192
+ registerOpenAIDecisions(pi, config, refresh);
1105
1193
  registerOpenAILive(pi, config);
1106
1194
  registerOpenAIPets(pi, {
1107
1195
  wake: async (ctx, slug) => {
@@ -1270,8 +1358,9 @@ export default function betterOpenAI(pi: ExtensionAPI): void {
1270
1358
 
1271
1359
  const modelName = ctx.model?.id || "no-model";
1272
1360
  const thinkingLevel = pi.getThinkingLevel();
1273
- const fastSuffix =
1274
- fastController.active && supportsFast(ctx, cfg.supportedModels) ? " fast" : "";
1361
+ const fastSuffix = fastController.statusSegment(ctx, cfg)
1362
+ ? ` ${fastController.desiredTier}`
1363
+ : "";
1275
1364
  let rightWithoutProvider = modelName;
1276
1365
  if (ctx.model?.reasoning) {
1277
1366
  rightWithoutProvider =
@@ -1448,7 +1537,9 @@ export default function betterOpenAI(pi: ExtensionAPI): void {
1448
1537
  fastController.initializeForSession(ctx, nextConfig, pi.getFlag(FLAG) === true);
1449
1538
  if (
1450
1539
  fastController.desiredActive !== nextConfig.desiredActive ||
1451
- fastController.active !== nextConfig.active
1540
+ fastController.active !== nextConfig.active ||
1541
+ fastController.desiredTier !==
1542
+ (nextConfig.serviceTier ?? (nextConfig.desiredActive ? "fast" : "standard"))
1452
1543
  )
1453
1544
  persist(nextConfig);
1454
1545
  if (hasTerminalUI(ctx)) petController.installResizeGuard(ctx);
@@ -1489,11 +1580,8 @@ export default function betterOpenAI(pi: ExtensionAPI): void {
1489
1580
  pi.on("turn_end", (event, ctx) => {
1490
1581
  invalidateContextUsage();
1491
1582
  if (event.message?.role === "assistant") {
1492
- footerTotals.input += event.message.usage.input;
1493
- footerTotals.output += event.message.usage.output;
1494
- footerTotals.cacheRead += event.message.usage.cacheRead;
1495
- footerTotals.cacheWrite += event.message.usage.cacheWrite;
1496
- footerTotals.cost += event.message.usage.cost.total;
1583
+ addFooterUsage(event.message.usage);
1584
+ for (const result of event.toolResults ?? []) addFooterUsage(result.usage);
1497
1585
  } else refreshFooterTotals(ctx);
1498
1586
  updateFooter(ctx);
1499
1587
  void usageController.refresh(ctx);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monotykamary/pi-better-openai",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
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",
@@ -38,6 +38,8 @@
38
38
  "index.ts",
39
39
  "src/",
40
40
  "README.md",
41
+ "CHANGELOG.md",
42
+ "plans/devday-integration.md",
41
43
  "LICENSE",
42
44
  "THIRD_PARTY_NOTICES.md"
43
45
  ],
@@ -52,7 +54,8 @@
52
54
  "lint": "oxlint --deny-warnings index.ts src/*.ts src/*/*.ts tests/*.ts",
53
55
  "lint:fix": "oxlint --fix index.ts src/*.ts src/*/*.ts tests/*.ts",
54
56
  "test": "vitest run",
55
- "typecheck": "tsc --noEmit"
57
+ "typecheck": "tsc --noEmit",
58
+ "test:pi": "node scripts/test-pi-compat.mjs"
56
59
  },
57
60
  "dependencies": {
58
61
  "https-proxy-agent": "9.1.0",
@@ -62,9 +65,9 @@
62
65
  "ws": "8.21.2"
63
66
  },
64
67
  "devDependencies": {
65
- "@earendil-works/pi-ai": "0.87.0",
66
- "@earendil-works/pi-coding-agent": "0.87.0",
67
- "@earendil-works/pi-tui": "0.87.0",
68
+ "@earendil-works/pi-ai": "0.99.0",
69
+ "@earendil-works/pi-coding-agent": "0.99.0",
70
+ "@earendil-works/pi-tui": "0.99.0",
68
71
  "@types/node": "~22.19.0",
69
72
  "@types/proxy-from-env": "1.0.4",
70
73
  "@types/ws": "8.18.1",
@@ -86,8 +89,8 @@
86
89
  "@oh-my-pi/pi-natives-win32-x64": "17.2.9"
87
90
  },
88
91
  "overrides": {
89
- "@earendil-works/pi-agent-core": "0.87.0",
90
- "@earendil-works/pi-ai": "0.87.0",
92
+ "@earendil-works/pi-agent-core": "0.99.0",
93
+ "@earendil-works/pi-ai": "0.99.0",
91
94
  "brace-expansion": "5.0.9",
92
95
  "nanoid": "3.3.18",
93
96
  "postcss": "8.5.25",
@@ -0,0 +1,48 @@
1
+ # DevDay integration status
2
+
3
+ Research checkpoint: September 29, 2026 (UTC). Announcements and account entitlements can change independently of source releases.
4
+
5
+ ## Implemented
6
+
7
+ - GPT-6.1 Sol fallback metadata, with native Pi transport/auth and live catalog precedence preserved.
8
+ - Fast-mode defaults for GPT-6 Astra, 6.1 Sol, Sol, and Luna on OpenAI/Codex.
9
+ - Explicit Standard/Fast/Ultrafast selection, legacy state migration, model/endpoint capability gates, persistence, diagnostics, cost disclosure, and footer labels.
10
+ - `openai_decide`: an opt-in bridge to Pi's classifier API. Explicit model selection, bounded typed input/output, cancellation/deadlines, usage reporting, and no chat/provider fallback.
11
+ - No autonomous actions, model routing, approval bypasses, or inference-driven polling. Classification is an advisory primitive; application code owns policy and execution.
12
+
13
+ ## Native OpenAI Decisions: blocked on a verifiable contract
14
+
15
+ The announcement is reported in [DevDay coverage](https://www.axios.com/2026/09/29/openai-dev-day-2026-dots-space-sol). At the research checkpoint, the public docs index and OpenAI Node SDK did not expose a verifiable Decisions contract; Codex search hits concerned existing approval decisions. This is not proof that private or later access is unavailable.
16
+
17
+ The tool works with explicitly selected registered classifiers, including Jev. It does not pretend this is OpenAI's new service. Once OpenAI publishes its contract:
18
+
19
+ 1. Verify model IDs, schema, error/refusal behavior, modalities, endpoint, auth audience, rate limits, pricing, and data residency.
20
+ 2. Prefer a native Pi classifier adapter rather than duplicating credentials and transport here. Register classifier models, not chat models; the current tool can then select them.
21
+ 3. Preserve provider semantics. Do not equate arbitrary numeric scores or self-reported confidence with calibrated probabilities, or silently translate incompatible question types.
22
+ 4. Keep API-key and Codex subscription access separate until subscription authorization is documented. Do not infer OAuth compatibility from a product announcement.
23
+ 5. Add fixture tests and an opt-in live probe before claiming support. No default model ID is guessed today.
24
+
25
+ ### Evaluation checklist
26
+
27
+ Before automated routing or background triage is enabled, compare pinned Jev/OpenAI classifier versions on the same consented, non-sensitive labeled cases:
28
+
29
+ - failure classification, candidate-tool ranking, task routing, and notification relevance;
30
+ - p50/p95 end-to-end latency, cost per useful decision, invalid-result/refusal/timeout rates;
31
+ - accuracy and abstention coverage; Brier score/calibration only for outputs documented as probabilities;
32
+ - low-confidence escalation and immutable policy/permission boundaries.
33
+
34
+ Do not automatically run paid benchmark requests. A typed result is not proof of truth or authorization. TypeSafe's [September 15 Jev announcement](https://typesafe.ai/blog/introducing-system-one-models-and-jev) establishes timing and the decision-oriented interface, not OpenAI implementation provenance.
35
+
36
+ ## Codex subscription Ultrafast: capability gate remains closed
37
+
38
+ The [public Ultrafast guide](https://developers.openai.com/api/docs/guides/ultrafast-mode) documents API Astra support. Codex has catalog-driven tier controls and WebSocket tier-switch tests, but its inspected bundled Astra/Sol catalog advertises Fast, not a subscription Ultrafast entitlement.
39
+
40
+ Enable subscription Ultrafast only after an authenticated model/account capability contract is established, with tests for account switching, capability withdrawal, and unsupported requests. Arbitrary `supportedModels` configuration must not bypass this gate. Global/US API Astra is the verified path today. Host cost reporting currently may omit its 6x premium; never describe local estimates as actual billing.
41
+
42
+ ## Hosted Responses multi-agent: deliberately deferred
43
+
44
+ [Responses multi-agent](https://developers.openai.com/api/docs/guides/responses-multi-agent) is a separate beta protocol, not a tier or ordinary thinking level. Adding only `multi_agent.enabled` is insufficient and could conflict with Fabric's orchestration.
45
+
46
+ A future opt-in integration must handle agent identities, hosted collaboration items versus client tool calls, interleaved streams, continuation routing, cancellation, concurrency and total-spend limits, and permission enforcement for every child. Do not assume `max_concurrent_subagents` limits total agents, tree depth, or total spend. Keep the existing local orchestration owner until these invariants are verified.
47
+
48
+ Dots, Space, and other consumer surfaces are not added without a documented integration contract.
@@ -59,6 +59,26 @@ export const CODEX_MODEL_FALLBACKS: CodexModel[] = [
59
59
  },
60
60
  compat: CODEX_COMPAT,
61
61
  },
62
+ {
63
+ id: "gpt-6.1-sol",
64
+ name: "GPT-6.1 Sol",
65
+ api: CODEX_API,
66
+ provider: CODEX_PROVIDER_ID,
67
+ baseUrl: CODEX_BASE_URL,
68
+ reasoning: true,
69
+ thinkingLevelMap: { off: null, minimal: "low", xhigh: "xhigh", max: "max" },
70
+ input: ["text", "image"],
71
+ contextWindow: 272000,
72
+ maxTokens: 128000,
73
+ cost: {
74
+ input: 2,
75
+ output: 10,
76
+ cacheRead: 0.1,
77
+ cacheWrite: 2.5,
78
+ tiers: [{ inputTokensAbove: 272000, input: 4, output: 15, cacheRead: 0.2, cacheWrite: 5 }],
79
+ },
80
+ compat: CODEX_COMPAT,
81
+ },
62
82
  {
63
83
  id: "gpt-daybreak-blue-latest",
64
84
  name: "Daybreak Blue",