feat(ai,coding-agent): add Grok 4.7 support

This commit is contained in:
Armin Ronacher 2026-09-22 00:07:34 +02:00
parent 1b6ddca87c
commit 1a584a7a56
9 changed files with 45 additions and 14 deletions

View file

@ -2,6 +2,10 @@
## [Unreleased]
### Added
- Added Grok 4.7 to the built-in xAI model catalog with long-context pricing metadata.
### Fixed
- Fixed image-only user messages being rejected by some OpenAI-compatible providers because they included an empty text part ([#9797](https://github.com/earendil-works/pi/issues/9797))

View file

@ -833,7 +833,7 @@ Many models support thinking/reasoning capabilities where they can show their in
const model = models.getModel('anthropic', 'claude-sonnet-4-5')!;
// or models.getModel('openai', 'gpt-5-mini');
// or models.getModel('google', 'gemini-2.5-flash');
// or models.getModel('xai', 'grok-4.6');
// or models.getModel('xai', 'grok-4.7');
// Check if model supports reasoning
if (model.reasoning) {

View file

@ -2030,12 +2030,7 @@ async function loadModelsDevData(): Promise<Model<any>[]> {
compat: { ...XAI_RESPONSES_COMPAT },
reasoning: m.reasoning === true,
input: m.modalities?.input?.includes("image") ? ["text", "image"] : ["text"],
cost: {
input: m.cost?.input || 0,
output: m.cost?.output || 0,
cacheRead: m.cost?.cache_read || 0,
cacheWrite: m.cost?.cache_write || 0,
},
cost: getModelsDevCost(m.cost),
contextWindow: m.limit?.context || 4096,
maxTokens: m.limit?.output || 4096,
});

View file

@ -8,6 +8,8 @@ it("derives model API, ID, and provider literals from grouped model data", () =>
expectTypeOf(XAI_MODELS["grok-4.5"].provider).toEqualTypeOf<"xai">();
expectTypeOf(XAI_MODELS["grok-4.6"].api).toEqualTypeOf<"openai-responses">();
expectTypeOf(XAI_MODELS["grok-4.6"].id).toEqualTypeOf<"grok-4.6">();
expectTypeOf(XAI_MODELS["grok-4.7"].api).toEqualTypeOf<"openai-responses">();
expectTypeOf(XAI_MODELS["grok-4.7"].id).toEqualTypeOf<"grok-4.7">();
expectTypeOf(XAI_MODELS["grok-4.3"].api).toEqualTypeOf<"openai-responses">();
});

View file

@ -540,8 +540,8 @@ describe("Generate E2E Tests", () => {
});
});
describe.skipIf(!process.env.XAI_API_KEY)("xAI Provider (grok-4.3 via OpenAI Responses)", () => {
const llm = getModel("xai", "grok-4.3");
describe.skipIf(!process.env.XAI_API_KEY)("xAI Provider (grok-4.7 via OpenAI Responses)", () => {
const llm = getModel("xai", "grok-4.7");
it("should complete basic text generation", { retry: 3 }, async () => {
await basicTextGeneration(llm);

View file

@ -132,9 +132,35 @@ describe("xAI Responses provider", () => {
}
expect(getSupportedThinkingLevels(XAI_MODELS["grok-4.5"])).toEqual(["low", "medium", "high"]);
expect(getSupportedThinkingLevels(XAI_MODELS["grok-4.6"])).toEqual(["low", "medium", "high", "xhigh"]);
expect(getSupportedThinkingLevels(XAI_MODELS["grok-4.7"])).toEqual(["low", "medium", "high", "xhigh"]);
expect(getSupportedThinkingLevels(XAI_MODELS["grok-4.3"])).toEqual(["off", "low", "medium", "high"]);
});
it("includes Grok 4.7 capabilities and long-context pricing", () => {
expect(XAI_MODELS["grok-4.7"]).toMatchObject({
api: "openai-responses",
reasoning: true,
input: ["text", "image"],
contextWindow: 500000,
maxTokens: 500000,
cost: {
input: 2,
output: 6,
cacheRead: 0.5,
cacheWrite: 0,
tiers: [
{
inputTokensAbove: 200000,
input: 4,
output: 12,
cacheRead: 1,
cacheWrite: 0,
},
],
},
});
});
it("uses /responses with bearer auth and xAI-compatible request fields", async () => {
const captured = await captureRequest(
XAI_MODELS["grok-4.5"],
@ -188,9 +214,9 @@ describe("xAI Responses provider", () => {
expect(captured.body).not.toHaveProperty("reasoning");
});
it("uses /responses for Grok 4.6 with xhigh effort and encrypted reasoning", async () => {
it("uses /responses for Grok 4.7 with xhigh effort and encrypted reasoning", async () => {
const captured = await captureRequest(
XAI_MODELS["grok-4.6"],
XAI_MODELS["grok-4.7"],
{
systemPrompt: "You are a careful coding assistant.",
messages: [{ role: "user", content: "hello", timestamp: 1 }],
@ -203,7 +229,7 @@ describe("xAI Responses provider", () => {
expect(captured.url).toBe("https://api.x.ai/v1/responses");
expect(captured.body).toMatchObject({
model: "grok-4.6",
model: "grok-4.7",
store: false,
stream: true,
reasoning: { effort: "xhigh" },

View file

@ -2,6 +2,10 @@
## [Unreleased]
### Changed
- Changed the default xAI model to Grok 4.7.
## [0.87.0] - 2026-09-21
### New Features

View file

@ -32,7 +32,7 @@ export const defaultModelPerProvider: Record<KnownProvider, string> = {
"github-copilot": "gpt-5.4",
openrouter: "moonshotai/kimi-k2.6",
"vercel-ai-gateway": "zai/glm-5.1",
xai: "grok-4.6",
xai: "grok-4.7",
groq: "openai/gpt-oss-120b",
cerebras: "gpt-oss-120b",
zai: "glm-5.3",

View file

@ -735,7 +735,7 @@ describe("default model selection", () => {
});
test("xai default tracks current model", () => {
expect(defaultModelPerProvider.xai).toBe("grok-4.6");
expect(defaultModelPerProvider.xai).toBe("grok-4.7");
});
test("qwen token plan individual default tracks current model", () => {