diff --git a/docs/provider-quirks.md b/docs/provider-quirks.md index 674342249..08a1a4c60 100644 --- a/docs/provider-quirks.md +++ b/docs/provider-quirks.md @@ -1566,7 +1566,7 @@ xAI Grok OAuth provides subscription-backed access (SuperGrok / X Premium+) to x - **Usage Tracking**: `xaiOauthUsageProvider` (`packages/ai/src/usage/xai-oauth.ts`) queries `https://cli-chat-proxy.grok.com/v1/billing` (`validateXAIBillingEndpoint` pins to HTTPS `*.grok.com`) with header `X-XAI-Token-Auth: xai-grok-cli` (`getXAICliBillingHeaders`). Only accepts valid OAuth bearer credentials. Probes legacy weekly credits (`?format=credits`, `parseWeeklyBillingConfig` for `creditUsagePercent` and `productUsage`) and unified monthly quota (`parseMonthlyBillingConfig` for `monthlyLimit` and `used`), plus positive `onDemandCap` / `onDemandUsed` limits. ### Catalog model handling -- **Curated Models & Static Seed**: `XAI_OAUTH_CURATED_MODELS` (`packages/catalog/src/provider-models/openai-compat.ts`) defines static models (`grok-build`, `grok-build-0.1`, `grok-4.3`, `grok-4.5`, `grok-4.20-multi-agent-0309`, `grok-4.20-0309-reasoning`, `grok-4.20-0309-non-reasoning`, `grok-composer-2.5-fast`) with zero cost (`cost: 0`). Default model is `grok-4.3` (`descriptors.ts`). `buildXaiOAuthStaticSeed` seeds `ModelRegistry` synchronously at boot so `modelRoles.default = "xai-oauth/"` works before dynamic refresh. +- **Curated Models & Static Seed**: `XAI_OAUTH_CURATED_MODELS` (`packages/catalog/src/provider-models/openai-compat.ts`) defines static models (`grok-build`, `grok-build-0.1`, `grok-4.3`, `grok-4.5`, `grok-4.6`, `grok-4.20-multi-agent-0309`, `grok-4.20-0309-reasoning`, `grok-4.20-0309-non-reasoning`, `grok-composer-2.5-fast`) with zero cost (`cost: 0`). Default model is `grok-4.6` (`descriptors.ts`). `buildXaiOAuthStaticSeed` seeds `ModelRegistry` synchronously at boot so `modelRoles.default = "xai-oauth/"` works before dynamic refresh. - **Dynamic Curation Overlay**: `applyXAIOAuthCuration` (`openai-compat.ts`, `xaiOAuthModelManagerOptions`) filters non-chat prefixes (`grok-imagine-`, `grok-stt-`, `grok-voice-`), overlays curated context windows (up to 2M), sets `maxTokens` equal to `contextWindow`, preserves image capabilities and reasoning flags, and injects missing curated models. - **Reference Resolution Exclusion**: `isZeroCostXaiOAuthCandidate` (`packages/catalog/src/identity/reference.ts`) excludes zero-cost subscription entries from reference index matching so subscription pricing and limits do not override public/paid Grok references. diff --git a/packages/ai/src/auth-storage.ts b/packages/ai/src/auth-storage.ts index 82441706b..e9f4f4417 100644 --- a/packages/ai/src/auth-storage.ts +++ b/packages/ai/src/auth-storage.ts @@ -2698,7 +2698,7 @@ export class AuthStorage { /** * Whether a request could resolve a key for this provider, including * cross-provider env aliases (`xai-oauth` borrowing `XAI_API_KEY`). - * Use this for explicit model preflight (`xai-oauth/grok-4.5`); use + * Use this for explicit model preflight (`xai-oauth/grok-4.6`); use * {@link hasAuth} for auto-availability so the default picker stays on * paid `xai` when only `XAI_API_KEY` is set. */ @@ -2732,8 +2732,8 @@ export class AuthStorage { * `getEnvApiKey("xai-oauth")` also accepts `XAI_API_KEY` so an explicit * `xai-oauth/…` stream can still borrow the paid key. Availability and * origin must not: otherwise an API-key-only setup marks SuperGrok as - * signed in and `pickDefaultAvailableModel` prefers `xai-oauth/grok-4.5` - * over paid `xai/grok-4.5`. + * signed in and `pickDefaultAvailableModel` prefers `xai-oauth/grok-4.6` + * over paid `xai/grok-4.6`. */ #hasDedicatedEnvAuth(provider: string): boolean { if (provider === "xai-oauth") { diff --git a/packages/catalog/CHANGELOG.md b/packages/catalog/CHANGELOG.md index 9822535f3..3d3f8bc94 100644 --- a/packages/catalog/CHANGELOG.md +++ b/packages/catalog/CHANGELOG.md @@ -6,6 +6,11 @@ - Raised the GPT-5.6 Sol/Terra/Luna context window on the Codex transport (openai-codex) from 372K to 1M tokens: OpenAI enabled the 1M window for subscription Codex on 2026-08-16, but the Codex model registry still reports the stale 272,000, so discovery now floors these SKUs at 1,000,000 instead of trusting the reported value ([openai/codex#38917](https://github.com/openai/codex/issues/38917)). +### Changed + +- Changed the paid xAI (XAI_API_KEY) and SuperGrok (xai-oauth) default models to grok-4.6. + + ## [17.3.5] - 2026-08-16 ### Added diff --git a/packages/catalog/src/provider-models/descriptors.ts b/packages/catalog/src/provider-models/descriptors.ts index dc1d2afc3..c7bd9ad29 100644 --- a/packages/catalog/src/provider-models/descriptors.ts +++ b/packages/catalog/src/provider-models/descriptors.ts @@ -478,13 +478,13 @@ export const CATALOG_PROVIDERS = [ }, { id: "xai", - defaultModel: "grok-4.5", + defaultModel: "grok-4.6", envVars: ["XAI_API_KEY"], createModelManagerOptions: (config: ModelManagerConfig) => xaiModelManagerOptions(config), }, { id: "xai-oauth", - defaultModel: "grok-4.5", + defaultModel: "grok-4.6", envVars: ["XAI_OAUTH_TOKEN", "XAI_API_KEY"], createModelManagerOptions: (config: ModelManagerConfig) => xaiOAuthModelManagerOptions(config), catalogDiscovery: { diff --git a/packages/catalog/test/xai-api-key-responses.test.ts b/packages/catalog/test/xai-api-key-responses.test.ts index c11849cec..97b75def6 100644 --- a/packages/catalog/test/xai-api-key-responses.test.ts +++ b/packages/catalog/test/xai-api-key-responses.test.ts @@ -4,7 +4,7 @@ import * as os from "node:os"; import * as path from "node:path"; import { resolveProviderModels } from "@oh-my-pi/pi-catalog/model-manager"; import { getBundledModels } from "@oh-my-pi/pi-catalog/models"; -import { CATALOG_PROVIDERS } from "@oh-my-pi/pi-catalog/provider-models/descriptors"; +import { CATALOG_PROVIDERS, DEFAULT_MODEL_PER_PROVIDER } from "@oh-my-pi/pi-catalog/provider-models/descriptors"; import { xaiModelManagerOptions } from "@oh-my-pi/pi-catalog/provider-models/openai-compat"; import type { ModelSpec } from "@oh-my-pi/pi-catalog/types"; @@ -37,13 +37,18 @@ describe("paid xai (XAI_API_KEY) Responses contract", () => { it("registers xai on the catalog Responses discovery path", () => { const entry = CATALOG_PROVIDERS.find(provider => provider.id === "xai"); expect(entry, "xai catalog descriptor").toBeDefined(); - expect(entry!.defaultModel).toBe("grok-4.5"); + expect(entry!.defaultModel).toBe("grok-4.6"); + expect(DEFAULT_MODEL_PER_PROVIDER.xai).toBe("grok-4.6"); + expect( + getBundledModels("xai").find(model => model.id === "grok-4.6"), + "xai/grok-4.6 must be bundled for the default", + ).toBeDefined(); expect(entry!.envVars).toContain("XAI_API_KEY"); const options = xaiModelManagerOptions({ apiKey: "test-key" }); expect(options.providerId).toBe("xai"); expect(options.fetchDynamicModels, "live /v1/models overlay").toBeTypeOf("function"); expect(options.dropCachedModelIdsOnStaticMismatch).toEqual(getBundledModels("xai").map(model => model.id)); - expect(options.dropCachedModelIdsOnStaticMismatch).toContain("grok-4.5"); + expect(options.dropCachedModelIdsOnStaticMismatch).toContain("grok-4.6"); }); it("bundles every paid xai chat model on openai-responses", () => { diff --git a/packages/catalog/test/xai-oauth-bundle.test.ts b/packages/catalog/test/xai-oauth-bundle.test.ts index 534cc488c..8a16a7a55 100644 --- a/packages/catalog/test/xai-oauth-bundle.test.ts +++ b/packages/catalog/test/xai-oauth-bundle.test.ts @@ -18,11 +18,11 @@ describe("xai-oauth bundled catalog (regression)", () => { (MODELS_JSON as unknown as Record>>)["xai-oauth"] ?? {}; const seed = buildXaiOAuthStaticSeed(); - it("defaults SuperGrok selection to grok-4.5", () => { + it("defaults SuperGrok selection to grok-4.6", () => { const entry = CATALOG_PROVIDERS.find(provider => provider.id === "xai-oauth"); - expect(entry?.defaultModel).toBe("grok-4.5"); - expect(DEFAULT_MODEL_PER_PROVIDER["xai-oauth"]).toBe("grok-4.5"); - expect(bundled["grok-4.5"], "xai-oauth/grok-4.5 must be bundled for the default").toBeDefined(); + expect(entry?.defaultModel).toBe("grok-4.6"); + expect(DEFAULT_MODEL_PER_PROVIDER["xai-oauth"]).toBe("grok-4.6"); + expect(bundled["grok-4.6"], "xai-oauth/grok-4.6 must be bundled for the default").toBeDefined(); }); it("bundles every curated id", () => { diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 089640459..5959c1831 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Changed + +- Updated the default model for XAI_API_KEY (xai) and SuperGrok OAuth (xai-oauth) to grok-4.6. Automatic model selection continues to prefer paid xai/grok-4.6 when only XAI_API_KEY is set, with xai-oauth/grok-4.6 still available explicitly. + ### Added - Added `ExtensionAPI.registerFileWriteFallback(handler)` and `ExtensionAPI.registerFileDeleteFallback(handler)`, letting an extension supply a fallback writer or deleter that is consulted when a native `write`, `edit`, or `apply_patch` byte-write or unlink is denied with a permission error (`EPERM`/`EACCES`/`EROFS`) — for hosts that embed the agent inside a sandbox that denies direct filesystem access but exposes a privileged channel. The brokered path is symlink-resolved so a handler's allowlist sees the real destination, a destination that cannot be resolved is not brokered at all, and `req.sessionId` names the session that issued the mutation so a handler sharing the process-wide registry can enforce policy per session. See [`docs/extensions.md`](../../docs/extensions.md). diff --git a/packages/coding-agent/test/model-resolver.test.ts b/packages/coding-agent/test/model-resolver.test.ts index 6d0e2d86d..8b6cedd52 100644 --- a/packages/coding-agent/test/model-resolver.test.ts +++ b/packages/coding-agent/test/model-resolver.test.ts @@ -1,6 +1,7 @@ import { describe, expect, test } from "bun:test"; import { type Api, Effort, type Model } from "@oh-my-pi/pi-ai"; import { buildModel } from "@oh-my-pi/pi-catalog/build"; +import { getBundledModel } from "@oh-my-pi/pi-catalog/models"; import { DEFAULT_MODEL_PER_PROVIDER } from "@oh-my-pi/pi-catalog/provider-models"; import { expandRoleAlias, @@ -439,30 +440,11 @@ describe("pickDefaultAvailableModel", () => { }); test("prefers SuperGrok over paid xAI when both defaults are present", () => { - const paid = buildModel({ - id: "grok-4.5", - name: "Grok 4.5", - api: "openai-responses", - provider: "xai", - baseUrl: "https://api.x.ai/v1", - reasoning: true, - input: ["text", "image"], - cost: { input: 2, output: 6, cacheRead: 0.3, cacheWrite: 0 }, - contextWindow: 500000, - maxTokens: 500000, - }); - const oauth = buildModel({ - id: "grok-4.5", - name: "Grok 4.5", - api: "openai-responses", - provider: "xai-oauth", - baseUrl: "https://api.x.ai/v1", - reasoning: true, - input: ["text", "image"], - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - contextWindow: 500000, - maxTokens: 500000, - }); + const paid = getBundledModel("xai", DEFAULT_MODEL_PER_PROVIDER.xai); + const oauth = getBundledModel("xai-oauth", DEFAULT_MODEL_PER_PROVIDER["xai-oauth"]); + if (!paid || !oauth) { + throw new Error("Expected bundled xAI provider defaults"); + } expect(pickDefaultAvailableModel([paid, oauth])?.provider).toBe("xai-oauth"); expect(pickDefaultAvailableModel([paid])?.provider).toBe("xai");