/** * Better OpenAI for pi. * * Adds capability-gated OpenAI service tiers and opt-in native typed decisions. */ import { type ExtensionAPI, type ExtensionContext, type Theme, type ThemeColor, } from "@earendil-works/pi-coding-agent"; import { Container, Key, matchesKey, SettingsList, type SettingsListTheme, } from "@earendil-works/pi-tui"; import type { Usage } from "@earendil-works/pi-ai"; import { registerOpenAICodexModels } from "./src/codex-models.ts"; import { CONFIG_BASENAME, STATUS_KEY } from "./src/identity.ts"; import { CODEX_PROVIDER_ID, isMultiproviderService, MULTIPROVIDER_SERVICE_EVENT, setActiveMultiproviderService, type MultiproviderService, } from "./src/multiprovider.ts"; import { formatTokens, redactDiagnosticValue, sanitizeDiagnosticError, sanitizeStatusText, truncateToWidth, visibleWidth, } from "./src/format.ts"; import { DEFAULT_CONFIG, DEFAULT_IMAGE_CONFIG, DEFAULT_LIVE_CONFIG, DEFAULT_PET_CONFIG, DEFAULT_SUPPORTED_MODELS, DEFAULT_WEBSEARCH_CONFIG, PET_STATES, FOOTER_SETTING_DESCRIPTORS, USAGE_SETTING_DESCRIPTORS, IMAGE_SETTING_DESCRIPTORS, WEBSEARCH_SETTING_DESCRIPTORS, LIVE_SETTING_DESCRIPTORS, PET_SETTING_DESCRIPTORS, FAST_SETTING_DESCRIPTORS, DECISIONS_SETTING_DESCRIPTORS, isServiceTier, type SettingsOptionDescriptor, configPaths, type ResolvedConfig, type PetState, isRecord, parseModelKey, normalizeModelKeys, parseModels, readRawConfig, resolveConfig, writeConfig, applySettingToRawConfig, } from "./src/config.ts"; import { type UsageSegment, type UsageSeverity, formatPercent, formatUsageSnapshot, parseUsageSnapshot, readCodexAuth, } from "./src/usage.ts"; import { buildBankedResetConfirmation, formatBankedResetChoice, formatConsumeOutcome, selectBankedResetCredit, } from "./src/resets.ts"; import { ResetController } from "./src/reset-controller.ts"; import { registerOpenAIImage, _imageTest } from "./src/image.ts"; import { registerOpenAIWebSearch, _websearchTest } from "./src/websearch.ts"; import { registerOpenAILive } from "./src/live/index.ts"; import { registerOpenAIDecisions } from "./src/decisions.ts"; import { type CodexPetPackage, codexHome, describeCodexPetSelectionIssue, findCodexPet, findReadyCodexPet, formatNoReadyCodexPetsMessage, listCodexPets, registerOpenAIPets, _petsTest, } from "./src/pets.ts"; import { FastController, supportsFast } from "./src/fast-controller.ts"; import { isOpenAISubscriptionModel, UsageController } from "./src/usage-controller.ts"; import { PetFooterController } from "./src/pet-footer-controller.ts"; import { abbreviateHomePath, combineInlinePetFooter, isInlinePetPlacement, isTerminalImageLine, petSizeCellsForPlacement, } from "./src/footer-layout.ts"; // pi-core's getSettingsListTheme pulls the host module graph into this // extension's loader (~0.5s of startup). The settings picker is a command-time // surface, so the theme loads when it first opens. let loadedSettingsListTheme: SettingsListTheme | undefined; const loadSettingsListTheme = async (): Promise => { loadedSettingsListTheme ??= ( await import("@earendil-works/pi-coding-agent") ).getSettingsListTheme(); return loadedSettingsListTheme; }; const requireSettingsListTheme = (): SettingsListTheme => { if (!loadedSettingsListTheme) { throw new Error("Settings list theme accessed before /openai-settings preload"); } return loadedSettingsListTheme; }; const USAGE_SEVERITY_COLORS: Record = { ok: "success", warning: "warning", critical: "error", muted: "dim", }; /** * Keep a coloured segment on one line. Unlike sanitizeStatusText this leaves the * spacing shared by neighbouring segments ("Usage: " + "5h: " + "90%") intact. */ function flattenSegment(text: string): string { return text.replace(/[\r\n\t]+/g, " "); } /** * Colour a usage line segment by segment: the percentages carry the severity * colour while the labels, countdowns and banked resets stay dim. */ function colorizeUsageSegments(segments: UsageSegment[], theme: Theme): string { return segments .map((segment) => theme.fg(USAGE_SEVERITY_COLORS[segment.severity], flattenSegment(segment.text)), ) .join(""); } /** Pair the fast-mode segment with the usage segments for the status widget. */ function statusWidgetParts( fast: string | undefined, usage: UsageSegment[] | undefined, ): UsageSegment[] | undefined { const parts: UsageSegment[] = fast ? [{ text: fast, severity: "muted" }] : []; if (usage?.length) { if (parts.length > 0) parts.push({ text: " · ", severity: "muted" }); parts.push(...usage); } return parts.length > 0 ? parts : undefined; } class DynamicBorder { readonly #color: (text: string) => string; constructor(color: (text: string) => string = (str) => str) { this.#color = color; } invalidate(): void {} render(width: number): string[] { return [this.#color("\u2500".repeat(Math.max(1, width)))]; } } const COMMAND = "fast"; const OPENAI_STATUS_COMMAND = "openai-usage"; const OPENAI_SETTINGS_COMMAND = "openai-settings"; const OPENAI_RESETS_COMMAND = "openai-resets"; const FLAG = "fast"; const PET_EMPTY_VALUE = "not selected"; const SERVICE_TIER = "priority"; type SettingsPickerItem = { id: string; label: string; description?: string; currentValue: string; values?: string[]; submenu?: ( currentValue: string, done: (selectedValue?: string) => void, ) => { render(width: number): string[]; invalidate(): void; handleInput?(data: string): void }; }; function hasTerminalUI(ctx: ExtensionContext): boolean { return ctx.mode === "tui" || (ctx.mode === undefined && ctx.hasUI); } function readyPetPickerValues(pets: CodexPetPackage[]): string[] | undefined { const readyPets = pets.filter((pet) => pet.hasSpritesheet); return readyPets.length > 0 ? readyPets.map((pet) => pet.slug) : undefined; } function petConfigPickerValue(cfg: ResolvedConfig): string { return cfg.pets.slug || PET_EMPTY_VALUE; } function petSlugFromPickerValue(value: string): string { return value === PET_EMPTY_VALUE ? "" : value; } function findPickerPet(value: string, pets: CodexPetPackage[]): CodexPetPackage | undefined { return findCodexPet( pets.filter((pet) => pet.hasSpritesheet), value, ); } function petPickerDescription(cfg: ResolvedConfig, pets: CodexPetPackage[]): string { const readyPets = pets.filter((pet) => pet.hasSpritesheet); if (readyPets.length === 0) return "No ready custom pets found. Use /pets help to create one, then return here."; if (!cfg.pets.slug) { const firstPet = readyPets[0]!; const lastPet = readyPets[readyPets.length - 1]!; return `No pet selected. Enter/Space/→ selects ${firstPet.name}; ← selects ${lastPet.name}.`; } const selectedPet = findPickerPet(cfg.pets.slug, readyPets); const selected = selectedPet ? `Selected: ${selectedPet.name} (${selectedPet.slug})` : `Selected: ${cfg.pets.slug}`; return `${selected}. Enter/Space/→ cycles pets; ← cycles back. Preview appears in the footer while this menu is open.`; } function formatPetSelectPrompt( pets: CodexPetPackage[], home = codexHome(), ): { message: string; level: "info" | "warning" } { const readyPets = pets.filter((pet) => pet.hasSpritesheet); if (readyPets.length === 0) { return { message: formatNoReadyCodexPetsMessage(pets, home), level: "warning" }; } const brokenPets = pets.filter((pet) => !pet.hasSpritesheet); const lines = [ "Choose one with /pets select :", ...readyPets.map((pet) => `- ${pet.slug} (${pet.name})`), ]; if (brokenPets.length > 0) { lines.push( "", "Not ready:", ...brokenPets.map( (pet) => `- ${pet.slug} (${pet.name}) — ${pet.spritesheetIssue ?? `missing ${pet.spritesheetPath}`}`, ), ); } return { message: lines.join("\n"), level: "info" }; } function textPanel(title: string, lines: string[], done: () => void) { return { render(width: number) { const clipped = lines.map((line) => truncateToWidth(line, width, "...")); return [title, "", ...clipped, "", "Esc/q to go back"]; }, invalidate() {}, handleInput(data: string) { if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c")) || data === "q") done(); }, }; } export default function betterOpenAI(pi: ExtensionAPI): void { registerOpenAICodexModels(pi); const fastController = new FastController(SERVICE_TIER); let cachedConfig: ResolvedConfig | undefined; let footerTotals = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 }; let footerInstalled = false; let statusInstalled = false; let statusWidgetInstalled = false; let contextUsageCached = false; let cachedContextUsage: ReturnType; let cachedContextLeafId: string | null | undefined; let cachedContextModel: ExtensionContext["model"]; let sessionNameCached = false; let cachedSessionNameLeafId: string | null | undefined; let cachedSessionName: string | undefined; const usageController = new UsageController(config, updateFooter); const resetController = new ResetController( (ctx) => hasTerminalUI(ctx) && config(ctx).usage.autoRedeemBankedResets, (ctx) => { void usageController.refresh(ctx, ctx.model?.id, { force: true }); }, ); const petController = new PetFooterController(config, updateFooter, () => footerInstalled); let multiproviderService: MultiproviderService | undefined; let unsubscribeMultiprovider: (() => void) | undefined; let multiproviderRefreshCtx: ExtensionContext | undefined; // Follow pi-multiprovider's active pooled account for openai-codex. The // event re-fires with the same stable object at load and session start; the // identity check keeps the change subscription attached exactly once. When // the extension is absent, nothing here activates and credential resolution // keeps its standalone behavior. if (typeof pi.events?.on === "function") { pi.events.on(MULTIPROVIDER_SERVICE_EVENT, (value) => { if (!isMultiproviderService(value) || value === multiproviderService) return; unsubscribeMultiprovider?.(); multiproviderService = value; setActiveMultiproviderService(value); unsubscribeMultiprovider = value.onActiveAccountChanged(CODEX_PROVIDER_ID, (event) => { void usageController.refresh(event.ctx, undefined, { force: true }); void resetController.refresh(event.ctx, { force: true }).catch(() => {}); updateFooter(event.ctx); }); const ctx = multiproviderRefreshCtx; if (ctx) { void usageController.refresh(ctx, undefined, { force: true }); updateFooter(ctx); } }); } function refresh(ctx: ExtensionContext): ResolvedConfig { cachedConfig = resolveConfig(ctx.cwd || process.cwd()); return cachedConfig; } function config(ctx: ExtensionContext): ResolvedConfig { return cachedConfig ?? refresh(ctx); } function persist(nextConfig: ResolvedConfig): void { cachedConfig = { ...nextConfig, active: fastController.active, desiredActive: fastController.desiredActive, serviceTier: fastController.desiredTier, }; if (!nextConfig.persistState) return; writeConfig(nextConfig.configPath, { ...readRawConfig(nextConfig.configPath), active: fastController.active, desiredActive: fastController.desiredActive, serviceTier: fastController.desiredTier, }); } function writePetConfig(ctx: ExtensionContext, patch: Record): ResolvedConfig { const cfg = refresh(ctx); const current = readRawConfig(cfg.configPath); const pets = isRecord(current.pets) ? current.pets : {}; writeConfig(cfg.configPath, { ...current, pets: { ...pets, ...patch } }); petController.invalidateLoadKey(); return refresh(ctx); } function setActive(ctx: ExtensionContext, next: boolean): void { const nextConfig = refresh(ctx); fastController.setDesired(ctx, nextConfig, next); persist(nextConfig); updateFooter(ctx); if (next && !fastController.active) { ctx.ui.notify(fastController.unsupportedRequestMessage(ctx, nextConfig), "warning"); return; } ctx.ui.notify(fastController.stateText(ctx, nextConfig), "info"); } function addFooterUsage(usage: Usage | undefined): void { if (!usage) return; footerTotals.input += usage.input; footerTotals.output += usage.output; footerTotals.cacheRead += usage.cacheRead; footerTotals.cacheWrite += usage.cacheWrite; footerTotals.cost += usage.cost.total; } function refreshFooterTotals(ctx: ExtensionContext): void { footerTotals = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 }; for (const entry of ctx.sessionManager.getEntries()) { if (entry.type !== "message") continue; if (entry.message.role === "assistant" || entry.message.role === "toolResult") { addFooterUsage(entry.message.usage); } } } function invalidateContextUsage(): void { contextUsageCached = false; cachedContextUsage = undefined; cachedContextLeafId = undefined; cachedContextModel = undefined; } function contextUsage(ctx: ExtensionContext): ReturnType { const leafId = ctx.sessionManager.getLeafId(); const model = ctx.model; if (!contextUsageCached || leafId !== cachedContextLeafId || model !== cachedContextModel) { cachedContextUsage = ctx.getContextUsage(); contextUsageCached = true; cachedContextLeafId = leafId; cachedContextModel = model; } return cachedContextUsage; } function sessionName(ctx: ExtensionContext): string | undefined { const leafId = ctx.sessionManager.getLeafId(); if (!sessionNameCached || leafId !== cachedSessionNameLeafId) { cachedSessionName = ctx.sessionManager.getSessionName(); cachedSessionNameLeafId = leafId; sessionNameCached = true; } return cachedSessionName; } function invalidateSessionName(): void { sessionNameCached = false; cachedSessionNameLeafId = undefined; cachedSessionName = undefined; } pi.registerFlag(FLAG, { description: "Start with OpenAI fast mode enabled (service_tier=priority)", type: "boolean", default: false, }); function formatDebugStatus(ctx: ExtensionContext): string { const cfg = config(ctx); return [ ...fastController.debugLines(ctx, cfg), `Footer mode: ${cfg.footer.mode}`, "", usageController.formatDebug(ctx), "", `Image enabled: ${cfg.image.enabled}`, `Image default save: ${cfg.image.defaultSave}`, `Websearch enabled: ${cfg.websearch.enabled}`, `Websearch model: ${cfg.websearch.model} (${cfg.websearch.reasoningEffort}/${cfg.websearch.responseLength}, ${cfg.websearch.maxOutputTokens} tokens, ${cfg.websearch.timeoutMs}ms)`, `Decisions enabled: ${cfg.decisions.enabled}`, `Decision classifier: ${cfg.decisions.model || "not selected"} (${cfg.decisions.timeoutMs}ms)`, "Native OpenAI Decisions requires a registered classifier adapter; no chat fallback.", `Live enabled: ${cfg.live.enabled}`, `Live voice: ${cfg.live.voice}`, `Pet enabled: ${cfg.pets.enabled}`, `Pet slug: ${cfg.pets.slug || PET_EMPTY_VALUE}`, `Pet placement: ${cfg.pets.placement}`, `Pet failed tool state: ${cfg.pets.failedToolState}`, `Pet idle emotes: ${cfg.pets.idleEmotes} (${cfg.pets.idleEmoteIntervalMs}ms)`, `Pet loaded: ${petController.loadedPet?.pet.name ?? "none"}`, `Pet error: ${petController.error ?? "none"}`, `Config: ${cfg.configPath}`, ].join("\n"); } async function redeemBankedReset(ctx: ExtensionContext): Promise { const resume = resetController.pauseAutoRedeem(); try { await chooseBankedReset(ctx); } finally { resume(); } } async function chooseBankedReset(ctx: ExtensionContext): Promise { if (!hasTerminalUI(ctx)) { ctx.ui.notify("/openai-resets requires an interactive TUI session.", "warning"); return; } let credits = resetController.snapshot?.credits; if (!credits) { await resetController.refresh(ctx, { force: true }).catch(() => {}); credits = resetController.snapshot?.credits; } if (!credits) { const reason = resetController.lastError; ctx.ui.notify(`Banked reset lookup failed${reason ? `: ${reason}` : "."}`, "error"); return; } void resetController.refresh(ctx).catch(() => {}); if (credits.availableCount <= 0) { ctx.ui.notify("No banked Codex resets are available for this account.", "info"); return; } const available = credits.credits.filter((credit) => credit.status === "available"); let selected = selectBankedResetCredit(credits.credits); if (available.length > 1 && selected) { const options = available.map((credit, index) => formatBankedResetChoice(credit, index, config(ctx).usage.autoRedeemBankedResets), ); const chosen = await ctx.ui.select("Redeem which banked reset?", options); if (chosen === undefined) { ctx.ui.notify("Banked reset redemption cancelled.", "info"); return; } selected = available[options.indexOf(chosen)]; } if (!selected) { ctx.ui.notify( "No individually identifiable banked reset is available; nothing was redeemed.", "warning", ); return; } const confirmation = buildBankedResetConfirmation({ credit: selected, autoRedeem: config(ctx).usage.autoRedeemBankedResets, availableCount: credits.availableCount, snapshot: usageController.snapshot, }); if (!(await ctx.ui.confirm(confirmation.title, confirmation.message))) { ctx.ui.notify("Banked reset redemption cancelled.", "info"); return; } try { const result = await resetController.redeem(ctx, selected.id); const outcome = formatConsumeOutcome(result); ctx.ui.notify(outcome.message, outcome.level); void usageController.refresh(ctx, ctx.model?.id, { force: true }); void resetController.refresh(ctx, { force: true }).catch(() => {}); updateFooter(ctx); } catch (error) { ctx.ui.notify( `Banked reset redemption failed: ${sanitizeDiagnosticError( error instanceof Error ? error.message : String(error), )}`, "error", ); } } pi.registerCommand(COMMAND, { description: "Toggle OpenAI fast mode", handler: async (args, ctx) => { const arg = args.trim().toLowerCase(); if (!arg) return setActive(ctx, !fastController.desiredActive); ctx.ui.notify("Usage: /fast", "error"); }, }); pi.registerCommand("openai-tier", { description: "Select standard, fast, or ultrafast (API Astra; 6x Standard token prices)", handler: async (args, ctx) => { const tier = args.trim().toLowerCase(); if (!tier) { ctx.ui.notify( `Requested tier: ${fastController.desiredTier}. ${fastController.stateText(ctx, config(ctx))}`, "info", ); return; } if (!isServiceTier(tier)) { ctx.ui.notify( "Usage: /openai-tier [standard | fast | ultrafast]. Ultrafast explicitly opts into 6x Standard token prices.", "error", ); return; } const cfg = refresh(ctx); fastController.setTier(ctx, cfg, tier); persist(cfg); updateFooter(ctx); ctx.ui.notify( fastController.stateText(ctx, cfg), tier === "ultrafast" || (fastController.desiredActive && !fastController.active) ? "warning" : "info", ); }, }); pi.registerCommand(OPENAI_STATUS_COMMAND, { description: "Show OpenAI subscription usage status", handler: async (_args, ctx) => { await usageController.refresh(ctx, ctx.model?.id, { notify: true, force: true }); }, }); pi.registerCommand(OPENAI_RESETS_COMMAND, { description: "Inspect and redeem Codex banked rate-limit resets", handler: async (_args, ctx) => { await redeemBankedReset(ctx); }, }); function buildPetSettingsItems(cfg: ResolvedConfig): SettingsPickerItem[] { return settingsItemsFromDescriptors(PET_SETTING_DESCRIPTORS, cfg, { "pets.slug": { currentValue: petConfigPickerValue(cfg), values: readyPetPickerValues(petController.settingsPets), description: petPickerDescription(cfg, petController.settingsPets), }, }); } function petPreviewFromItem(item: SettingsPickerItem | undefined): PetState | undefined { if ( item?.id !== "pets.state" && item?.id !== "pets.thinkingState" && item?.id !== "pets.toolState" && item?.id !== "pets.failedToolState" ) return undefined; const value = item.currentValue; return (PET_STATES as readonly string[]).includes(value) ? (value as PetState) : undefined; } function renderPetSettingsPreview(ctx: ExtensionContext, width: number): string[] { return petController.renderSettingsPreview(ctx, width); } function settingsSubmenu( title: string, items: () => SettingsPickerItem[], ctx: ExtensionContext, done: () => void, options?: { onSelection?: (item: SettingsPickerItem | undefined) => void; onClose?: () => void; renderExtra?: (width: number) => string[]; }, ) { const theme = requireSettingsListTheme(); let selectedIndex = 0; let searchQuery = ""; let closed = false; let submenuComponent: ReturnType> | undefined; let submenuItemIndex: number | undefined; function currentItems(): SettingsPickerItem[] { const allItems = items(); const query = searchQuery.trim().toLowerCase(); const current = query ? allItems.filter((item) => item.label.toLowerCase().includes(query)) : allItems; selectedIndex = Math.max(0, Math.min(selectedIndex, Math.max(0, current.length - 1))); return current; } function selectedItem(): SettingsPickerItem | undefined { return currentItems()[selectedIndex]; } function close(): void { closed = true; options?.onClose?.(); done(); } function closeNestedSubmenu(): void { submenuComponent = undefined; if (submenuItemIndex !== undefined) selectedIndex = submenuItemIndex; submenuItemIndex = undefined; options?.onSelection?.(selectedItem()); } function cycleSelected(direction: 1 | -1 = 1): void { const item = selectedItem(); if (!item?.values?.length) return; const currentIndex = item.values.indexOf(item.currentValue); const startIndex = currentIndex === -1 ? (direction === 1 ? -1 : 0) : currentIndex; const newValue = item.values[(startIndex + direction + item.values.length) % item.values.length] ?? item.currentValue; writeSetting(ctx, item.id, newValue); options?.onSelection?.(selectedItem()); } function activateSelected(): void { const item = selectedItem(); if (!item) return; if (item.submenu) { submenuItemIndex = selectedIndex; submenuComponent = item.submenu(item.currentValue, (selectedValue?: string) => { if (selectedValue !== undefined) writeSetting(ctx, item.id, selectedValue); closeNestedSubmenu(); }); return; } cycleSelected(1); } return { render(width: number) { if (submenuComponent) return submenuComponent.render(width); const current = currentItems(); const selected = selectedItem(); if (!closed) options?.onSelection?.(selected); const lines = [theme.label(title, true), "", `> ${searchQuery}`, ""]; const maxVisible = 8; const startIndex = Math.max( 0, Math.min(selectedIndex - Math.floor(maxVisible / 2), current.length - maxVisible), ); const visible = current.slice(startIndex, startIndex + maxVisible); if (current.length === 0) { lines.push(theme.hint(" No matching settings")); lines.push("", theme.hint(" Type to search · Esc to go back")); return lines; } const maxLabelWidth = Math.min( 30, Math.max(1, ...current.map((item) => visibleWidth(item.label))), ); for (let i = 0; i < visible.length; i++) { const item = visible[i]; if (!item) continue; const itemIndex = startIndex + i; const isSelected = itemIndex === selectedIndex; const prefix = isSelected ? theme.cursor : " "; const labelPadded = item.label + " ".repeat(Math.max(0, maxLabelWidth - visibleWidth(item.label))); const valueMaxWidth = Math.max(1, width - visibleWidth(prefix) - maxLabelWidth - 4); lines.push( truncateToWidth( prefix + theme.label(labelPadded, isSelected) + " " + theme.value(truncateToWidth(item.currentValue, valueMaxWidth, ""), isSelected), width, ), ); } if (selected?.description) { lines.push( "", theme.description(` ${truncateToWidth(selected.description, width - 4)}`), ); } const extraLines = options?.renderExtra?.(width) ?? []; if (extraLines.length > 0) { lines.push(""); for (const line of extraLines) { lines.push(isTerminalImageLine(line) ? line : truncateToWidth(line, width, "...")); } } lines.push( "", theme.hint(" Type to search · ↑↓ navigate · ←→/Enter/Space to change · Esc to go back"), ); return lines; }, invalidate() { submenuComponent?.invalidate(); }, handleInput(data: string) { if (submenuComponent) { submenuComponent.handleInput?.(data); return; } const current = currentItems(); if (current.length === 0) { if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c"))) close(); else if (matchesKey(data, Key.backspace)) searchQuery = searchQuery.slice(0, -1); else if (data.length === 1 && data >= "!" && data <= "~") searchQuery += data; return; } if (matchesKey(data, Key.up)) selectedIndex = selectedIndex === 0 ? current.length - 1 : selectedIndex - 1; else if (matchesKey(data, Key.down)) selectedIndex = selectedIndex === current.length - 1 ? 0 : selectedIndex + 1; else if ( matchesKey(data, Key.right) || matchesKey(data, Key.enter) || matchesKey(data, Key.space) || data === " " ) activateSelected(); else if (matchesKey(data, Key.left)) cycleSelected(-1); else if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c"))) close(); else if (matchesKey(data, Key.backspace)) { searchQuery = searchQuery.slice(0, -1); selectedIndex = 0; } else if (data.length === 1 && data >= "!" && data <= "~") { searchQuery += data; selectedIndex = 0; } if (!closed) options?.onSelection?.(selectedItem()); }, }; } function fastSettingsSummary(ctx: ExtensionContext, cfg: ResolvedConfig): string { return fastController.settingsSummary(ctx, cfg); } function usageSettingsSummary(cfg: ResolvedConfig): string { return cfg.usage.enabled ? `enabled · ${Math.round(cfg.usage.refreshIntervalMs / 1000)}s` : "disabled"; } function imageSettingsSummary(cfg: ResolvedConfig): string { return cfg.image.enabled ? `enabled · ${cfg.image.defaultModel} · ${cfg.image.defaultSave}/${cfg.image.outputFormat}` : "disabled"; } function websearchSettingsSummary(cfg: ResolvedConfig): string { return cfg.websearch.enabled ? `enabled · ${cfg.websearch.model} · ${cfg.websearch.reasoningEffort}/${cfg.websearch.responseLength}` : "disabled"; } function liveSettingsSummary(cfg: ResolvedConfig): string { return cfg.live.enabled ? `enabled · ${cfg.live.voice}` : "disabled"; } function petSettingsSummary(cfg: ResolvedConfig): string { const selected = cfg.pets.slug || (cfg.pets.enabled ? "first ready" : PET_EMPTY_VALUE); const status = cfg.pets.enabled ? "enabled" : "disabled"; return `${status} · ${selected} · ${cfg.pets.placement}`; } type SettingsItemOverrides = Record< string, Partial> >; function settingsItemsFromDescriptors( descriptors: readonly SettingsOptionDescriptor[], cfg: ResolvedConfig, overrides: SettingsItemOverrides = {}, ): SettingsPickerItem[] { return descriptors.map((descriptor) => { const override = overrides[descriptor.id] ?? {}; const values = override.values ?? descriptor.values; return { id: descriptor.id, label: descriptor.label, currentValue: override.currentValue ?? descriptor.currentValue(cfg), values: values ? [...values] : undefined, description: override.description ?? descriptor.description, }; }); } function buildFastSettingsItems(cfg: ResolvedConfig): SettingsPickerItem[] { return settingsItemsFromDescriptors(FAST_SETTING_DESCRIPTORS, cfg, { serviceTier: { currentValue: fastController.desiredTier }, }); } function buildFooterSettingsItems(cfg: ResolvedConfig): SettingsPickerItem[] { return settingsItemsFromDescriptors(FOOTER_SETTING_DESCRIPTORS, cfg); } function buildUsageSettingsItems(cfg: ResolvedConfig): SettingsPickerItem[] { return settingsItemsFromDescriptors(USAGE_SETTING_DESCRIPTORS, cfg); } function buildImageSettingsItems(cfg: ResolvedConfig): SettingsPickerItem[] { return settingsItemsFromDescriptors(IMAGE_SETTING_DESCRIPTORS, cfg); } function buildWebsearchSettingsItems(cfg: ResolvedConfig): SettingsPickerItem[] { return settingsItemsFromDescriptors(WEBSEARCH_SETTING_DESCRIPTORS, cfg); } function buildLiveSettingsItems(cfg: ResolvedConfig): SettingsPickerItem[] { return settingsItemsFromDescriptors(LIVE_SETTING_DESCRIPTORS, cfg); } function buildDiagnosticsSettingsItems( ctx: ExtensionContext, cfg: ResolvedConfig, ): SettingsPickerItem[] { return [ { id: "debug", label: "Debug info", currentValue: "open", description: "Show Better OpenAI diagnostics.", submenu: (_value, done) => textPanel("Debug info", formatDebugStatus(ctx).split("\n"), () => done()), }, { id: "config.path", label: "Config path", currentValue: cfg.configPath, description: `Project: ${cfg.projectConfigPath}\nGlobal: ${cfg.globalConfigPath}`, }, { id: "config.print", label: "Print config", currentValue: "open", description: "Show the selected config JSON with sensitive fields redacted.", submenu: (_value, done) => textPanel( "Config", JSON.stringify(redactDiagnosticValue(readRawConfig(cfg.configPath)), null, 2).split( "\n", ), () => done(), ), }, ]; } function buildSettingsSections(ctx: ExtensionContext, cfg: ResolvedConfig): SettingsPickerItem[] { return [ { id: "section.fast", label: "Service tier", currentValue: fastSettingsSummary(ctx, cfg), description: "Configure Standard, Fast, Ultrafast, and persistence. Ultrafast costs 6x Standard.", submenu: (_value, done) => settingsSubmenu( "Service tier settings", () => buildFastSettingsItems(config(ctx)), ctx, () => done(fastSettingsSummary(ctx, config(ctx))), ), }, { id: "section.footer", label: "Footer", currentValue: cfg.footer.mode, description: "Configure Better OpenAI footer ownership.", submenu: (_value, done) => settingsSubmenu( "Footer settings", () => buildFooterSettingsItems(config(ctx)), ctx, () => done(config(ctx).footer.mode), ), }, { id: "section.usage", label: "Usage", currentValue: usageSettingsSummary(cfg), description: "Configure subscription usage fetching and display.", submenu: (_value, done) => settingsSubmenu( "Usage settings", () => buildUsageSettingsItems(config(ctx)), ctx, () => done(usageSettingsSummary(config(ctx))), ), }, { id: "section.image", label: "Image tool", currentValue: imageSettingsSummary(cfg), description: "Configure OpenAI image generation defaults.", submenu: (_value, done) => settingsSubmenu( "Image tool settings", () => buildImageSettingsItems(config(ctx)), ctx, () => done(imageSettingsSummary(config(ctx))), ), }, { id: "section.websearch", label: "Web search tool", currentValue: websearchSettingsSummary(cfg), description: "Configure ChatGPT Codex web search defaults.", submenu: (_value, done) => settingsSubmenu( "Web search tool settings", () => buildWebsearchSettingsItems(config(ctx)), ctx, () => done(websearchSettingsSummary(config(ctx))), ), }, { id: "section.decisions", label: "Typed decisions", currentValue: cfg.decisions.enabled ? cfg.decisions.model || "model required" : "disabled", description: "Opt-in native classifier requests; no chat fallback or automatic actions.", submenu: (_value, done) => settingsSubmenu( "Typed decision settings", () => { const next = config(ctx); const models = ctx.modelRegistry.getModelsOfType("classifier"); return settingsItemsFromDescriptors(DECISIONS_SETTING_DESCRIPTORS, next, { "decisions.model": { values: [ ...new Set([ "", next.decisions.model, ...models.map((model) => `${model.provider}/${model.id}`), ]), ], }, }); }, ctx, () => done( config(ctx).decisions.enabled ? config(ctx).decisions.model || "model required" : "disabled", ), ), }, { id: "section.live", label: "Live voice", currentValue: liveSettingsSummary(cfg), description: "Configure Codex-backed realtime voice mode.", submenu: (_value, done) => settingsSubmenu( "Live voice settings", () => buildLiveSettingsItems(config(ctx)), ctx, () => done(liveSettingsSummary(config(ctx))), ), }, { id: "section.pets", label: "Footer pet", currentValue: petSettingsSummary(cfg), description: "Configure footer pet visibility, animation-state mapping, and size.", submenu: (_value, done) => { petController.setSettingsPreviewActive(ctx, true); return settingsSubmenu( "Footer pet settings", () => buildPetSettingsItems(config(ctx)), ctx, () => done(petSettingsSummary(config(ctx))), { onSelection: (item) => { const previewState = petPreviewFromItem(item); if (previewState !== petController.previewState) { petController.setPreviewState(previewState); updateFooter(ctx); } }, onClose: () => { petController.setPreviewState(undefined); petController.setSettingsPreviewActive(ctx, false); updateFooter(ctx); }, renderExtra: (width) => renderPetSettingsPreview(ctx, width), }, ); }, }, { id: "section.diagnostics", label: "Diagnostics", currentValue: "debug / config", description: "Show Better OpenAI diagnostics and raw config details.", submenu: (_value, done) => settingsSubmenu( "Diagnostics", () => buildDiagnosticsSettingsItems(ctx, config(ctx)), ctx, () => done("debug / config"), ), }, ]; } function writeSetting(ctx: ExtensionContext, id: string, rawValue: string): void { const cfg = refresh(ctx); const current = readRawConfig(cfg.configPath); const bool = rawValue === "true"; if (id === "fast.enabled") { fastController.setDesired(ctx, cfg, bool); } else if (id === "serviceTier") { if (!isServiceTier(rawValue)) return; fastController.setTier(ctx, cfg, rawValue); ctx.ui.notify( fastController.stateText(ctx, cfg), rawValue === "ultrafast" || (fastController.desiredActive && !fastController.active) ? "warning" : "info", ); } const petKey = id.startsWith("pets.") ? id.slice("pets.".length) : undefined; const nextRawConfig = applySettingToRawConfig(current, id, rawValue, { persistState: cfg.persistState, active: fastController.active, desiredActive: fastController.desiredActive, serviceTier: fastController.desiredTier, petEmptyValue: PET_EMPTY_VALUE, }); if (id === "persistState" && bool) { nextRawConfig.serviceTier = fastController.desiredTier; nextRawConfig.active = fastController.active; nextRawConfig.desiredActive = fastController.desiredActive; } if (petKey) { if (petKey === "enabled" || petKey === "sizeCells" || petKey === "slug") petController.invalidateLoadKey(); if (petKey === "placement" || petKey === "sizeCells" || petKey === "slug") petController.resetRenderCache(); if (petKey === "idleEmotes" || petKey === "idleEmoteIntervalMs") petController.stopIdleEmotes(); } writeConfig(cfg.configPath, nextRawConfig); const next = refresh(ctx); if (id === "pets.enabled" || id === "pets.sizeCells" || id === "pets.slug") void petController.refresh(ctx, next); if (id.startsWith("usage.")) { usageController.restartAfterSettingsChange(ctx, next); resetController.start(ctx); } updateFooter(ctx); } async function showSettingsPicker(ctx: ExtensionContext): Promise { if (!hasTerminalUI(ctx)) { ctx.ui.notify("Better OpenAI settings require interactive TUI mode.", "warning"); return; } await loadSettingsListTheme(); try { petController.settingsPets = await listCodexPets(); } catch { petController.settingsPets = []; } try { await ctx.ui.custom((tui, theme, _kb, done) => { petController.setSettingsRenderRequest(() => tui.requestRender()); const container = new Container(); container.addChild(new DynamicBorder((text) => theme.fg("border", text))); container.addChild( new (class { render(_width: number) { const cfg = config(ctx); return [ theme.bold(theme.fg("accent", "Better OpenAI Settings")), theme.fg("muted", cfg.configPath), "", ]; } invalidate() {} })(), ); const settingsList = new SettingsList( buildSettingsSections(ctx, refresh(ctx)), 8, requireSettingsListTheme(), (id, newValue) => { if (!id.startsWith("section.")) writeSetting(ctx, id, newValue); settingsList.updateValue( id, buildSettingsSections(ctx, config(ctx)).find((item) => item.id === id) ?.currentValue ?? newValue, ); tui.requestRender(); }, () => done(undefined), { enableSearch: true }, ); container.addChild(settingsList); container.addChild(new DynamicBorder((text) => theme.fg("border", text))); return { render(width: number) { return container.render(width); }, invalidate() { container.invalidate(); }, handleInput(data: string) { settingsList.handleInput(data); tui.requestRender(); }, }; }); } finally { petController.setSettingsRenderRequest(undefined); petController.setPreviewState(undefined); petController.setSettingsPreviewActive(ctx, false); updateFooter(ctx); } } pi.registerCommand(OPENAI_SETTINGS_COMMAND, { description: "Open Better OpenAI settings picker", handler: async (_args, ctx) => { await showSettingsPicker(ctx); }, }); registerOpenAIImage(pi, config); registerOpenAIWebSearch(pi, config); registerOpenAIDecisions(pi, config, refresh); registerOpenAILive(pi, config); registerOpenAIPets(pi, { wake: async (ctx, slug) => { const pets = await listCodexPets(); const requestedSlug = (slug ?? config(ctx).pets.slug) || undefined; const selectedPet = findReadyCodexPet(pets, requestedSlug); if (!selectedPet) { const issue = describeCodexPetSelectionIssue(pets, requestedSlug); ctx.ui.notify(issue.message, "warning"); return; } const next = writePetConfig(ctx, { enabled: true, slug: selectedPet.slug, }); updateFooter(ctx); if (hasTerminalUI(ctx)) await petController.refresh(ctx, next, true); else ctx.ui.notify( `Enabled ${selectedPet.name} (${selectedPet.slug}); footer pets render in interactive TUI mode.`, "info", ); }, tuck: (ctx) => { writePetConfig(ctx, { enabled: false }); petController.tuck(); updateFooter(ctx); ctx.ui.notify("Footer pet tucked away.", "info"); }, select: async (ctx, slug) => { const pets = await listCodexPets(); if (!slug) { const prompt = formatPetSelectPrompt(pets); ctx.ui.notify(prompt.message, prompt.level); return; } const selectedPet = findReadyCodexPet(pets, slug); if (!selectedPet) { const issue = describeCodexPetSelectionIssue(pets, slug); ctx.ui.notify(issue.message, "warning"); return; } const next = writePetConfig(ctx, { slug: selectedPet.slug }); updateFooter(ctx); if (petController.shouldLoadForConfig(next)) { if (hasTerminalUI(ctx)) await petController.refresh(ctx, next, true); else ctx.ui.notify( `Selected ${selectedPet.name} (${selectedPet.slug}); footer pets render in interactive TUI mode.`, "info", ); } else { ctx.ui.notify( `Selected ${selectedPet.name} (${selectedPet.slug}) for the footer pet. Use /pets wake to show it.`, "info", ); } }, }); function installFooter(ctx: ExtensionContext): void { if (footerInstalled) { petController.requestFooterRenderNow(); return; } footerInstalled = true; ctx.ui.setFooter((tui, theme, footerData) => { petController.setFooterRenderRequest(() => tui.requestRender()); const unsubscribe = footerData.onBranchChange?.(() => tui.requestRender()); let lastFooterSizeKey: string | undefined; return { dispose: () => { unsubscribe?.(); petController.stopIdleEmotes(); petController.stopAnimation(); petController.stopPendingRenderRequest(); petController.disposeKittyNow(); footerInstalled = false; petController.setFooterRenderRequest(undefined); }, invalidate() { petController.queueKittyCleanup(); petController.resetRenderCache(); }, render(width: number): string[] { const now = Date.now(); const footerSizeKey = `${width}:${process.stdout.rows ?? 0}`; if (lastFooterSizeKey !== undefined && lastFooterSizeKey !== footerSizeKey) { petController.freezeForResize(ctx, now); } lastFooterSizeKey = footerSizeKey; const freezePetFrame = petController.isResizeFrozen(now); const totalInput = footerTotals.input; const totalOutput = footerTotals.output; const totalCacheRead = footerTotals.cacheRead; const totalCacheWrite = footerTotals.cacheWrite; const totalCost = footerTotals.cost; let pwd = abbreviateHomePath(ctx.sessionManager.getCwd()); const branch = footerData.getGitBranch?.(); if (branch) pwd = `${pwd} (${branch})`; const currentSessionName = sessionName(ctx); if (currentSessionName) pwd = `${pwd} • ${currentSessionName}`; const parts: string[] = []; if (totalInput) parts.push(`↑${formatTokens(totalInput)}`); if (totalOutput) parts.push(`↓${formatTokens(totalOutput)}`); if (totalCacheRead) parts.push(`R${formatTokens(totalCacheRead)}`); if (totalCacheWrite) parts.push(`W${formatTokens(totalCacheWrite)}`); const usingSubscription = ctx.model ? ctx.modelRegistry.isUsingOAuth(ctx.model) : false; if (totalCost || usingSubscription) parts.push(`$${totalCost.toFixed(3)}${usingSubscription ? " (sub)" : ""}`); const currentContextUsage = contextUsage(ctx); const contextWindow = currentContextUsage?.contextWindow ?? ctx.model?.contextWindow ?? 0; const contextPercentValue = currentContextUsage?.percent ?? 0; const contextPercent = currentContextUsage?.percent !== null ? contextPercentValue.toFixed(1) : "?"; const contextDisplay = contextPercent === "?" ? `?/${formatTokens(contextWindow)} (auto)` : `${contextPercent}%/${formatTokens(contextWindow)} (auto)`; const contextText = contextPercentValue > 90 ? theme.fg("error", contextDisplay) : contextPercentValue > 70 ? theme.fg("warning", contextDisplay) : contextDisplay; parts.push(contextText); const cfg = config(ctx); const shouldRenderPet = petController.shouldRenderInFooter(cfg); const requestedPetPlacement = cfg.pets.placement; const requestedPetSizeCells = petSizeCellsForPlacement( requestedPetPlacement, cfg.pets.sizeCells, ); const inlinePet = Boolean( shouldRenderPet && petController.loadedPet && isInlinePetPlacement(requestedPetPlacement) && width >= requestedPetSizeCells + 32, ); const petRenderSizeCells = inlinePet ? requestedPetSizeCells : cfg.pets.sizeCells; const petColumnWidth = Math.min(petRenderSizeCells, Math.max(1, width - 1)); const footerTextWidth = inlinePet ? Math.max(1, width - petColumnWidth - 2) : width; const usageStatusSegments = usageController.statusSegments(ctx, cfg, usingSubscription); const usageLine = usageStatusSegments ? colorizeUsageSegments(usageStatusSegments, theme) : undefined; let statsLeft = parts.join(" "); let statsLeftWidth = visibleWidth(statsLeft); if (statsLeftWidth > footerTextWidth) { statsLeft = truncateToWidth(statsLeft, footerTextWidth, "..."); statsLeftWidth = visibleWidth(statsLeft); } const modelName = ctx.model?.id || "no-model"; const thinkingLevel = pi.getThinkingLevel(); const fastSuffix = fastController.statusSegment(ctx, cfg) ? ` ${fastController.desiredTier}` : ""; let rightWithoutProvider = modelName; if (ctx.model?.reasoning) { rightWithoutProvider = thinkingLevel === "off" ? `${modelName}${fastSuffix} • thinking off` : `${modelName}${fastSuffix} • ${thinkingLevel}`; } else if (fastSuffix) { rightWithoutProvider = `${modelName}${fastSuffix}`; } let rightSide = rightWithoutProvider; if ((footerData.getAvailableProviderCount?.() ?? 0) > 1 && ctx.model) { const withProvider = `(${ctx.model.provider}) ${rightWithoutProvider}`; if (statsLeftWidth + 2 + visibleWidth(withProvider) <= footerTextWidth) rightSide = withProvider; } const rightWidth = visibleWidth(rightSide); const totalNeeded = statsLeftWidth + 2 + rightWidth; let statsLine: string; if (totalNeeded <= footerTextWidth) { statsLine = statsLeft + " ".repeat(footerTextWidth - statsLeftWidth - rightWidth) + rightSide; } else { const availableForRight = footerTextWidth - statsLeftWidth - 2; if (availableForRight > 0) { const truncatedRight = truncateToWidth(rightSide, availableForRight, ""); statsLine = statsLeft + " ".repeat( Math.max(0, footerTextWidth - statsLeftWidth - visibleWidth(truncatedRight)), ) + truncatedRight; } else { statsLine = statsLeft; } } const textLines: string[] = [ truncateToWidth(theme.fg("dim", pwd), footerTextWidth, theme.fg("dim", "...")), theme.fg("dim", statsLeft) + theme.fg("dim", statsLine.slice(statsLeft.length)), ]; if (usageLine) { textLines.push(truncateToWidth(usageLine, footerTextWidth, theme.fg("dim", "..."))); } const extensionStatuses = footerData.getExtensionStatuses?.(); if (extensionStatuses?.size) { const statusLines = Array.from(extensionStatuses.entries()) .sort(([a], [b]) => String(a).localeCompare(String(b))) .map(([, text]) => theme.fg("dim", sanitizeStatusText(String(text)))); textLines.push( ...statusLines.map((line) => truncateToWidth(line, footerTextWidth, theme.fg("dim", "...")), ), ); } const petLines = petController.renderPetLines(ctx, cfg, { shouldRenderPet, freezePetFrame, requestedPetPlacement, petColumnWidth, petRenderSizeCells, width, theme, }); if (!shouldRenderPet || petLines.length === 0) return petController.withPendingKittyCleanup(textLines); if (inlinePet) { return petController.withPendingKittyCleanup( combineInlinePetFooter( petLines, textLines, width, requestedPetPlacement, petColumnWidth, ), ); } if (requestedPetPlacement === "habitat" && petController.loadedPet) { const label = ` ${petController.loadedPet.pet.name} `; const divider = theme.fg( "dim", truncateToWidth(`─${label}${"─".repeat(width)}`, width, ""), ); return petController.withPendingKittyCleanup([divider, ...petLines, ...textLines]); } return petController.withPendingKittyCleanup([...petLines, ...textLines]); }, }; }); } function clearFooter(ctx: ExtensionContext): void { if (!footerInstalled) return; petController.disposeKittyNow(); ctx.ui.setFooter(undefined); footerInstalled = false; petController.setFooterRenderRequest(undefined); } function setStatus(ctx: ExtensionContext, text: string | undefined): void { if (!text && !statusInstalled) return; ctx.ui.setStatus(STATUS_KEY, text); statusInstalled = text !== undefined; } function setStatusWidget(ctx: ExtensionContext, parts: UsageSegment[] | undefined): void { if (!parts && !statusWidgetInstalled) return; ctx.ui.setWidget( STATUS_KEY, parts ? (_tui, theme) => ({ invalidate() {}, render(width: number): string[] { const line = colorizeUsageSegments(parts, theme); return [truncateToWidth(line, width, theme.fg("dim", "..."))]; }, }) : undefined, { placement: "belowEditor" }, ); statusWidgetInstalled = parts !== undefined; } function updateFooter(ctx: ExtensionContext): void { const cfg = config(ctx); if (!hasTerminalUI(ctx)) { if (cfg.footer.mode === "off") { setStatus(ctx, undefined); return; } const fast = fastController.statusSegment(ctx, cfg); const usage = usageController.statusLine(ctx, cfg); setStatus(ctx, [fast, usage].filter(Boolean).join(" · ") || undefined); return; } petController.updateActivity(ctx, cfg); const shouldRenderPet = petController.shouldRenderInFooter(cfg); if (cfg.footer.mode === "replace" || shouldRenderPet) { setStatus(ctx, undefined); setStatusWidget(ctx, undefined); installFooter(ctx); return; } clearFooter(ctx); setStatus(ctx, undefined); if (cfg.footer.mode === "off") { setStatusWidget(ctx, undefined); return; } const fast = fastController.statusSegment(ctx, cfg); const usage = usageController.statusSegments(ctx, cfg); setStatusWidget(ctx, statusWidgetParts(fast, usage)); } pi.on("session_start", (_event, ctx) => { invalidateContextUsage(); invalidateSessionName(); multiproviderRefreshCtx = ctx; const nextConfig = refresh(ctx); fastController.initializeForSession(ctx, nextConfig, pi.getFlag(FLAG) === true); if ( fastController.desiredActive !== nextConfig.desiredActive || fastController.active !== nextConfig.active || fastController.desiredTier !== (nextConfig.serviceTier ?? (nextConfig.desiredActive ? "fast" : "standard")) ) persist(nextConfig); if (hasTerminalUI(ctx)) petController.installResizeGuard(ctx); refreshFooterTotals(ctx); updateFooter(ctx); if (hasTerminalUI(ctx) && nextConfig.pets.enabled) void petController.refresh(ctx, nextConfig); usageController.start(ctx); if ( hasTerminalUI(ctx) && (nextConfig.usage.autoRedeemBankedResets || (nextConfig.usage.enabled && isOpenAISubscriptionModel(ctx, nextConfig))) ) resetController.start(ctx); if (fastController.active) ctx.ui.notify(fastController.stateText(ctx, nextConfig), "info"); }); pi.on("agent_start", (_event, ctx) => { invalidateContextUsage(); petController.agentStart(ctx); updateFooter(ctx); }); pi.on("tool_execution_start", (event, ctx) => { petController.toolStart(ctx, event.toolCallId); updateFooter(ctx); }); pi.on("tool_execution_end", (event, ctx) => { petController.toolEnd(ctx, event.toolCallId, event.isError); if (!event.isError) updateFooter(ctx); }); pi.on("agent_end", (_event, ctx) => { petController.agentEnd(); updateFooter(ctx); }); pi.on("turn_end", (event, ctx) => { invalidateContextUsage(); if (event.message?.role === "assistant") { addFooterUsage(event.message.usage); for (const result of event.toolResults ?? []) addFooterUsage(result.usage); } else refreshFooterTotals(ctx); updateFooter(ctx); void usageController.refresh(ctx); }); pi.on("session_compact", (_event, ctx) => { invalidateContextUsage(); refreshFooterTotals(ctx); petController.queueKittyCleanup(); petController.resetRenderCache(); updateFooter(ctx); }); pi.on("session_tree", (_event, ctx) => { invalidateContextUsage(); refreshFooterTotals(ctx); petController.queueKittyCleanup(); petController.resetRenderCache(); updateFooter(ctx); }); pi.on("model_select", (event, ctx) => { invalidateContextUsage(); const cfg = config(ctx); const wasActive = fastController.active; fastController.applyDesiredState(ctx, cfg); if (fastController.active !== wasActive) { persist(cfg); if (cfg.notifyOnModelSwitch) { ctx.ui.notify( fastController.active ? fastController.stateText(ctx, cfg) : fastController.inactiveForModelMessage(ctx), fastController.active ? "info" : "warning", ); } } updateFooter(ctx); void usageController.refresh(ctx, event.model.id, { force: true }); }); pi.on("session_shutdown", () => { invalidateContextUsage(); invalidateSessionName(); multiproviderRefreshCtx = undefined; usageController.shutdown(); resetController.stop(); petController.shutdown(); }); pi.on("before_provider_request", (event, ctx) => { return fastController.injectProviderPayload(event, ctx, config(ctx)); }); pi.on("message_start", invalidateContextUsage); pi.on("message_update", invalidateContextUsage); pi.on("message_end", invalidateContextUsage); } export const _test = { CONFIG_BASENAME, DEFAULT_SUPPORTED_MODELS, DEFAULT_CONFIG, DEFAULT_IMAGE_CONFIG, DEFAULT_LIVE_CONFIG, DEFAULT_PET_CONFIG, DEFAULT_WEBSEARCH_CONFIG, SERVICE_TIER, configPaths, abbreviateHomePath, parseModelKey, normalizeModelKeys, parseModels, resolveConfig, readRawConfig, supportsFast, combineInlinePetFooter, PET_EMPTY_VALUE, readyPetPickerValues, petConfigPickerValue, petSlugFromPickerValue, petPickerDescription, formatPetSelectPrompt, parseUsageSnapshot, formatPercent, formatUsageSnapshot, readCodexAuth, textPanel, imageTest: _imageTest, websearchTest: _websearchTest, petsTest: _petsTest, };