fix(ai): prevent removed xAI models regenerating, closes #6736
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed Kimi Coding K3 thinking-level metadata to expose only the supported `max` level ([#6737](https://github.com/earendil-works/pi/issues/6737)).
|
- Fixed Kimi Coding K3 thinking-level metadata to expose only the supported `max` level ([#6737](https://github.com/earendil-works/pi/issues/6737)).
|
||||||
|
- Fixed catalog generation restoring xAI models removed in 0.80.9 ([#6736](https://github.com/earendil-works/pi/issues/6736)).
|
||||||
|
|
||||||
## [0.80.9] - 2026-07-16
|
## [0.80.9] - 2026-07-16
|
||||||
|
|
||||||
|
|||||||
@@ -747,7 +747,7 @@ Many models support thinking/reasoning capabilities where they can show their in
|
|||||||
const model = models.getModel('anthropic', 'claude-sonnet-4-5')!;
|
const model = models.getModel('anthropic', 'claude-sonnet-4-5')!;
|
||||||
// or models.getModel('openai', 'gpt-5-mini');
|
// or models.getModel('openai', 'gpt-5-mini');
|
||||||
// or models.getModel('google', 'gemini-2.5-flash');
|
// or models.getModel('google', 'gemini-2.5-flash');
|
||||||
// or models.getModel('xai', 'grok-code-fast-1');
|
// or models.getModel('xai', 'grok-4.5');
|
||||||
|
|
||||||
// Check if model supports reasoning
|
// Check if model supports reasoning
|
||||||
if (model.reasoning) {
|
if (model.reasoning) {
|
||||||
|
|||||||
@@ -302,6 +302,13 @@ const OPENAI_RESPONSES_NONE_REASONING_MODELS = new Set([
|
|||||||
"gpt-5.6-luna",
|
"gpt-5.6-luna",
|
||||||
]);
|
]);
|
||||||
const XAI_RESPONSES_MODEL_ID = "grok-4.5";
|
const XAI_RESPONSES_MODEL_ID = "grok-4.5";
|
||||||
|
const XAI_BUILTIN_EXCLUDED_MODEL_IDS = new Set([
|
||||||
|
"grok-3",
|
||||||
|
"grok-3-fast",
|
||||||
|
"grok-4.20-0309-non-reasoning",
|
||||||
|
"grok-4.20-0309-reasoning",
|
||||||
|
"grok-code-fast-1",
|
||||||
|
]);
|
||||||
const XAI_RESPONSES_EFFORT_LEVEL_MAP = {
|
const XAI_RESPONSES_EFFORT_LEVEL_MAP = {
|
||||||
off: null,
|
off: null,
|
||||||
minimal: null,
|
minimal: null,
|
||||||
@@ -1783,6 +1790,7 @@ async function generateModels() {
|
|||||||
// Combine models (models.dev has priority)
|
// Combine models (models.dev has priority)
|
||||||
const allModels = [...modelsDevModels, ...openRouterModels, ...aiGatewayModels].filter(
|
const allModels = [...modelsDevModels, ...openRouterModels, ...aiGatewayModels].filter(
|
||||||
(model) =>
|
(model) =>
|
||||||
|
!(model.provider === "xai" && XAI_BUILTIN_EXCLUDED_MODEL_IDS.has(model.id)) &&
|
||||||
!((model.provider === "opencode" || model.provider === "opencode-go") && model.id === "gpt-5.3-codex-spark"),
|
!((model.provider === "opencode" || model.provider === "opencode-go") && model.id === "gpt-5.3-codex-spark"),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -2142,56 +2150,6 @@ async function generateModels() {
|
|||||||
];
|
];
|
||||||
allModels.push(...codexModels);
|
allModels.push(...codexModels);
|
||||||
|
|
||||||
// Add missing Grok models
|
|
||||||
const missingGrokModels: Model<"openai-completions">[] = [
|
|
||||||
{
|
|
||||||
id: "grok-3",
|
|
||||||
name: "Grok 3",
|
|
||||||
api: "openai-completions",
|
|
||||||
baseUrl: "https://api.x.ai/v1",
|
|
||||||
provider: "xai",
|
|
||||||
reasoning: false,
|
|
||||||
input: ["text"],
|
|
||||||
cost: { input: 3, output: 15, cacheRead: 0.75, cacheWrite: 0 },
|
|
||||||
contextWindow: 131072,
|
|
||||||
maxTokens: 8192,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "grok-3-fast",
|
|
||||||
name: "Grok 3 Fast",
|
|
||||||
api: "openai-completions",
|
|
||||||
baseUrl: "https://api.x.ai/v1",
|
|
||||||
provider: "xai",
|
|
||||||
reasoning: false,
|
|
||||||
input: ["text"],
|
|
||||||
cost: { input: 5, output: 25, cacheRead: 1.25, cacheWrite: 0 },
|
|
||||||
contextWindow: 131072,
|
|
||||||
maxTokens: 8192,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "grok-code-fast-1",
|
|
||||||
name: "Grok Code Fast 1",
|
|
||||||
api: "openai-completions",
|
|
||||||
baseUrl: "https://api.x.ai/v1",
|
|
||||||
provider: "xai",
|
|
||||||
reasoning: false,
|
|
||||||
input: ["text"],
|
|
||||||
cost: {
|
|
||||||
input: 0.2,
|
|
||||||
output: 1.5,
|
|
||||||
cacheRead: 0.02,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 32768,
|
|
||||||
maxTokens: 8192,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
for (const model of missingGrokModels) {
|
|
||||||
if (!allModels.some(m => m.provider === model.provider && m.id === model.id)) {
|
|
||||||
allModels.push(model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add missing Mistral Medium 3.5 model until models.dev includes it
|
// Add missing Mistral Medium 3.5 model until models.dev includes it
|
||||||
if (!allModels.some(m => m.provider === "mistral" && m.id === "mistral-medium-3.5")) {
|
if (!allModels.some(m => m.provider === "mistral" && m.id === "mistral-medium-3.5")) {
|
||||||
allModels.push({
|
allModels.push({
|
||||||
|
|||||||
@@ -4706,9 +4706,9 @@ export const OPENROUTER_MODELS = {
|
|||||||
thinkingLevelMap: {"xhigh":"xhigh"},
|
thinkingLevelMap: {"xhigh":"xhigh"},
|
||||||
input: ["text"],
|
input: ["text"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0.9212,
|
input: 0.9198,
|
||||||
output: 2.8952,
|
output: 2.8908,
|
||||||
cacheRead: 0.17108,
|
cacheRead: 0.17082,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
contextWindow: 1048576,
|
contextWindow: 1048576,
|
||||||
|
|||||||
@@ -4,78 +4,6 @@
|
|||||||
import type { Model } from "../types.ts";
|
import type { Model } from "../types.ts";
|
||||||
|
|
||||||
export const XAI_MODELS = {
|
export const XAI_MODELS = {
|
||||||
"grok-3": {
|
|
||||||
id: "grok-3",
|
|
||||||
name: "Grok 3",
|
|
||||||
api: "openai-completions",
|
|
||||||
provider: "xai",
|
|
||||||
baseUrl: "https://api.x.ai/v1",
|
|
||||||
compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false},
|
|
||||||
reasoning: false,
|
|
||||||
input: ["text"],
|
|
||||||
cost: {
|
|
||||||
input: 3,
|
|
||||||
output: 15,
|
|
||||||
cacheRead: 0.75,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 131072,
|
|
||||||
maxTokens: 8192,
|
|
||||||
} satisfies Model<"openai-completions">,
|
|
||||||
"grok-3-fast": {
|
|
||||||
id: "grok-3-fast",
|
|
||||||
name: "Grok 3 Fast",
|
|
||||||
api: "openai-completions",
|
|
||||||
provider: "xai",
|
|
||||||
baseUrl: "https://api.x.ai/v1",
|
|
||||||
compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false},
|
|
||||||
reasoning: false,
|
|
||||||
input: ["text"],
|
|
||||||
cost: {
|
|
||||||
input: 5,
|
|
||||||
output: 25,
|
|
||||||
cacheRead: 1.25,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 131072,
|
|
||||||
maxTokens: 8192,
|
|
||||||
} satisfies Model<"openai-completions">,
|
|
||||||
"grok-4.20-0309-non-reasoning": {
|
|
||||||
id: "grok-4.20-0309-non-reasoning",
|
|
||||||
name: "Grok 4.20 (Non-Reasoning)",
|
|
||||||
api: "openai-completions",
|
|
||||||
provider: "xai",
|
|
||||||
baseUrl: "https://api.x.ai/v1",
|
|
||||||
compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false},
|
|
||||||
reasoning: false,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 1.25,
|
|
||||||
output: 2.5,
|
|
||||||
cacheRead: 0.2,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 1000000,
|
|
||||||
maxTokens: 30000,
|
|
||||||
} satisfies Model<"openai-completions">,
|
|
||||||
"grok-4.20-0309-reasoning": {
|
|
||||||
id: "grok-4.20-0309-reasoning",
|
|
||||||
name: "Grok 4.20 (Reasoning)",
|
|
||||||
api: "openai-completions",
|
|
||||||
provider: "xai",
|
|
||||||
baseUrl: "https://api.x.ai/v1",
|
|
||||||
compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false},
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 1.25,
|
|
||||||
output: 2.5,
|
|
||||||
cacheRead: 0.2,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 1000000,
|
|
||||||
maxTokens: 30000,
|
|
||||||
} satisfies Model<"openai-completions">,
|
|
||||||
"grok-4.3": {
|
"grok-4.3": {
|
||||||
id: "grok-4.3",
|
id: "grok-4.3",
|
||||||
name: "Grok 4.3",
|
name: "Grok 4.3",
|
||||||
@@ -131,22 +59,4 @@ export const XAI_MODELS = {
|
|||||||
contextWindow: 256000,
|
contextWindow: 256000,
|
||||||
maxTokens: 256000,
|
maxTokens: 256000,
|
||||||
} satisfies Model<"openai-completions">,
|
} satisfies Model<"openai-completions">,
|
||||||
"grok-code-fast-1": {
|
|
||||||
id: "grok-code-fast-1",
|
|
||||||
name: "Grok Code Fast 1",
|
|
||||||
api: "openai-completions",
|
|
||||||
provider: "xai",
|
|
||||||
baseUrl: "https://api.x.ai/v1",
|
|
||||||
compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false},
|
|
||||||
reasoning: false,
|
|
||||||
input: ["text"],
|
|
||||||
cost: {
|
|
||||||
input: 0.2,
|
|
||||||
output: 1.5,
|
|
||||||
cacheRead: 0.02,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 32768,
|
|
||||||
maxTokens: 8192,
|
|
||||||
} satisfies Model<"openai-completions">,
|
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ describe("Context overflow error handling", () => {
|
|||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
describe.skipIf(!process.env.XAI_API_KEY)("xAI", () => {
|
describe.skipIf(!process.env.XAI_API_KEY)("xAI", () => {
|
||||||
it("grok-3-fast - should detect overflow via isContextOverflow", async () => {
|
it("grok-4.3 - should detect overflow via isContextOverflow", async () => {
|
||||||
const model = getModel("xai", "grok-4.3");
|
const model = getModel("xai", "grok-4.3");
|
||||||
const result = await testContextOverflow(model, process.env.XAI_API_KEY!);
|
const result = await testContextOverflow(model, process.env.XAI_API_KEY!);
|
||||||
logResult(result);
|
logResult(result);
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ const PROVIDER_MODEL_PAIRS: ProviderModelPair[] = [
|
|||||||
label: "bedrock-claude-sonnet-4-5",
|
label: "bedrock-claude-sonnet-4-5",
|
||||||
},
|
},
|
||||||
// xAI
|
// xAI
|
||||||
{ provider: "xai", model: "grok-code-fast-1", label: "xai-grok-code-fast-1" },
|
{ provider: "xai", model: "grok-4.3", label: "xai-grok-4.3" },
|
||||||
// Cerebras
|
// Cerebras
|
||||||
{ provider: "cerebras", model: "zai-glm-4.7", label: "cerebras-zai-glm-4.7" },
|
{ provider: "cerebras", model: "zai-glm-4.7", label: "cerebras-zai-glm-4.7" },
|
||||||
// Cloudflare Workers AI
|
// Cloudflare Workers AI
|
||||||
|
|||||||
@@ -542,7 +542,7 @@ describe("Generate E2E Tests", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe.skipIf(!process.env.XAI_API_KEY)("xAI Provider (grok-code-fast-1 via OpenAI Completions)", () => {
|
describe.skipIf(!process.env.XAI_API_KEY)("xAI Provider (grok-4.3 via OpenAI Completions)", () => {
|
||||||
const llm = getModel("xai", "grok-4.3");
|
const llm = getModel("xai", "grok-4.3");
|
||||||
|
|
||||||
it("should complete basic text generation", { retry: 3 }, async () => {
|
it("should complete basic text generation", { retry: 3 }, async () => {
|
||||||
|
|||||||
@@ -244,22 +244,18 @@ describe("totalTokens field", () => {
|
|||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
describe.skipIf(!process.env.XAI_API_KEY)("xAI", () => {
|
describe.skipIf(!process.env.XAI_API_KEY)("xAI", () => {
|
||||||
it(
|
it("grok-4.3 - should return totalTokens equal to sum of components", { retry: 3, timeout: 60000 }, async () => {
|
||||||
"grok-3-fast - should return totalTokens equal to sum of components",
|
const llm = getModel("xai", "grok-4.3");
|
||||||
{ retry: 3, timeout: 60000 },
|
|
||||||
async () => {
|
|
||||||
const llm = getModel("xai", "grok-4.3");
|
|
||||||
|
|
||||||
console.log(`\nxAI / ${llm.id}:`);
|
console.log(`\nxAI / ${llm.id}:`);
|
||||||
const { first, second } = await testTotalTokensWithCache(llm, { apiKey: process.env.XAI_API_KEY });
|
const { first, second } = await testTotalTokensWithCache(llm, { apiKey: process.env.XAI_API_KEY });
|
||||||
|
|
||||||
logUsage("First request", first);
|
logUsage("First request", first);
|
||||||
logUsage("Second request", second);
|
logUsage("Second request", second);
|
||||||
|
|
||||||
assertTotalTokensEqualsComponents(first);
|
assertTotalTokensEqualsComponents(first);
|
||||||
assertTotalTokensEqualsComponents(second);
|
assertTotalTokensEqualsComponents(second);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|||||||
@@ -60,6 +60,18 @@ describe("xAI Responses provider", () => {
|
|||||||
vi.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("excludes retired and redundant models from the built-in catalog", () => {
|
||||||
|
for (const modelId of [
|
||||||
|
"grok-3",
|
||||||
|
"grok-3-fast",
|
||||||
|
"grok-4.20-0309-non-reasoning",
|
||||||
|
"grok-4.20-0309-reasoning",
|
||||||
|
"grok-code-fast-1",
|
||||||
|
]) {
|
||||||
|
expect(Object.keys(XAI_MODELS)).not.toContain(modelId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it("uses Responses with low/medium/high efforts only for Grok 4.5", () => {
|
it("uses Responses with low/medium/high efforts only for Grok 4.5", () => {
|
||||||
expect(XAI_MODELS["grok-4.5"].api).toBe("openai-responses");
|
expect(XAI_MODELS["grok-4.5"].api).toBe("openai-responses");
|
||||||
expect(getSupportedThinkingLevels(XAI_MODELS["grok-4.5"])).toEqual(["low", "medium", "high"]);
|
expect(getSupportedThinkingLevels(XAI_MODELS["grok-4.5"])).toEqual(["low", "medium", "high"]);
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed inherited catalog generation restoring xAI models removed in 0.80.9 ([#6736](https://github.com/earendil-works/pi/issues/6736)).
|
||||||
|
|
||||||
## [0.80.9] - 2026-07-16
|
## [0.80.9] - 2026-07-16
|
||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
|
|||||||
Reference in New Issue
Block a user