Skip to content

Commit b771e27

Browse files
committed
feat(models): add grok-4.7 model support
Exposes grok-4.7 wherever Grok models are offered, with the 500k context heuristic and the extended reasoning ladder (low/medium/ high default/xhigh) shared with grok-4.6. Prior Grok behavior unchanged. Fixes CL-8786
1 parent fc5e047 commit b771e27

7 files changed

Lines changed: 58 additions & 12 deletions

File tree

‎src/auth/xai/constants.ts‎

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,26 @@
11
import { XAI_REDIRECT_URI } from "@corbits/xai-provider";
22

3-
// Local alias over the vendor fallback list (CL-5691): XAI_DEFAULT_MODELS
4-
// backs live xAI catalog calls and stays in the vendor package — this alias
5-
// only renames the proxy URL. identity-divergence.test.ts pins the agreement.
6-
export {
7-
XAI_DEFAULT_MODELS,
3+
import {
4+
XAI_DEFAULT_MODELS as VENDOR_XAI_DEFAULT_MODELS,
85
XAI_OAUTH_PROXY_BASE_URL as XAI_BASE_URL,
9-
XAI_REDIRECT_URI,
106
XAI_REFRESH_SKEW_MS,
117
} from "@corbits/xai-provider";
128

9+
export { XAI_BASE_URL, XAI_REDIRECT_URI, XAI_REFRESH_SKEW_MS };
10+
11+
// Local extension over the vendor fallback list (CL-5691): grok-4.7 rides the
12+
// same OAuth proxy as the older Grok generations but the vendored catalog has
13+
// not caught up yet. The default stays the first vendor entry; drop this shim
14+
// once the vendor fallback lists grok-4.7 itself.
15+
const [firstVendorModel, secondVendorModel, ...restVendorModels] =
16+
VENDOR_XAI_DEFAULT_MODELS;
17+
export const XAI_DEFAULT_MODELS = [
18+
firstVendorModel,
19+
secondVendorModel,
20+
"grok-4.7",
21+
...restVendorModels,
22+
] as const;
23+
1324
const xaiRedirect = new URL(XAI_REDIRECT_URI);
1425
export const XAI_CALLBACK_PORT = Number(xaiRedirect.port);
1526
export const XAI_CALLBACK_PATH = xaiRedirect.pathname;

‎src/config/xai-providers.test.ts‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,14 @@ import {
1212
} from "./xai-providers.js";
1313

1414
describe("xAI OAuth provider projection", () => {
15-
test("default models include Grok 4.6 while defaulting to the CLI coding model", () => {
15+
test("default models include Grok 4.7 while defaulting to the CLI coding model", () => {
1616
const models: string[] = [...XAI_DEFAULT_MODELS];
17-
expect(models).toEqual(["grok-4.5", "grok-4.6", "grok-composer-2.5-fast"]);
17+
expect(models).toEqual([
18+
"grok-4.5",
19+
"grok-4.6",
20+
"grok-4.7",
21+
"grok-composer-2.5-fast",
22+
]);
1823
expect(models[0]).toBe("grok-4.5");
1924
});
2025

‎src/provider/context-window.test.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,11 @@ describe("contextWindowFor", () => {
2727
expect(contextWindowFor("xai/thegreataxios:grok-4.5")).toBe(500_000);
2828
});
2929

30-
it("falls back to a 500k grok-4.5/4.6 heuristic window when the registry has no entry", () => {
30+
it("falls back to a 500k grok-4.5/4.6/4.7 heuristic window when the registry has no entry", () => {
3131
setModelContextWindows(undefined);
3232
expect(contextWindowFor("xai/thegreataxios:grok-4.5")).toBe(500_000);
3333
expect(contextWindowFor("xai/thegreataxios:grok-4.6")).toBe(500_000);
34+
expect(contextWindowFor("xai/thegreataxios:grok-4.7")).toBe(500_000);
3435
expect(contextWindowFor("xai/thegreataxios:grok-4.3")).toBe(1_000_000);
3536
});
3637

‎src/provider/context-window.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,12 @@ function heuristicWindow(model: string): number {
9393
if (m.includes("glm-5.3")) return 1_000_000;
9494
if (m.includes("glm")) return 200_000;
9595
if (m.includes("o3") || m.includes("o4")) return 200_000;
96-
if (m.includes("grok-4.6") || m.includes("grok-4.5")) return 500_000;
96+
if (
97+
m.includes("grok-4.7") ||
98+
m.includes("grok-4.6") ||
99+
m.includes("grok-4.5")
100+
)
101+
return 500_000;
97102
if (m.includes("grok-4.3")) return 1_000_000;
98103
if (m.includes("grok") || m.includes("xai")) return 256_000;
99104
return DEFAULT_CONTEXT_WINDOW;

‎src/provider/reasoning-effort.test.ts‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,15 @@ describe("supportedEfforts", () => {
147147
]);
148148
});
149149

150+
test("grok-4.7 includes xhigh", () => {
151+
expect(supportedEfforts("grok-4.7")).toEqual([
152+
"low",
153+
"medium",
154+
"high",
155+
"xhigh",
156+
]);
157+
});
158+
150159
test("grok-4.5 stays on the unknown-model subset without xhigh", () => {
151160
expect(supportedEfforts("grok-4.5")).toEqual(["low", "medium", "high"]);
152161
});
@@ -223,6 +232,11 @@ describe("validateEffort", () => {
223232
expect(validateEffort("grok-4.5", "xhigh").ok).toBe(false);
224233
});
225234

235+
test("accepts xhigh on grok-4.7", () => {
236+
expect(validateEffort("grok-4.7", "xhigh")).toEqual({ ok: true });
237+
expect(validateEffort("grok-4.7", "minimal").ok).toBe(false);
238+
});
239+
226240
test("accepts minimal on Muse Spark and rejects none", () => {
227241
expect(validateEffort("muse-spark-1.3-contributor", "minimal")).toEqual({
228242
ok: true,
@@ -295,6 +309,12 @@ describe("cycleReasoningEffort", () => {
295309
expect(cycleReasoningEffort("grok-4.6", "high")).toBe("xhigh");
296310
expect(cycleReasoningEffort("grok-4.6", "xhigh")).toBe("low");
297311
});
312+
313+
test("wraps high to xhigh to low on grok-4.7", () => {
314+
expect(cycleReasoningEffort("grok-4.7", undefined)).toBe("xhigh");
315+
expect(cycleReasoningEffort("grok-4.7", "high")).toBe("xhigh");
316+
expect(cycleReasoningEffort("grok-4.7", "xhigh")).toBe("low");
317+
});
298318
});
299319

300320
describe("reasoning capability gate", () => {
@@ -504,6 +524,7 @@ describe("defaultEffortForModel", () => {
504524
afterEach(() => setModelReasoningCapabilities({}));
505525

506526
test("grok family defaults to high", () => {
527+
expect(defaultEffortForModel("grok-4.7")).toBe("high");
507528
expect(defaultEffortForModel("grok-4.6")).toBe("high");
508529
expect(defaultEffortForModel("grok-4.5")).toBe("high");
509530
});

‎src/provider/reasoning-effort.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,10 @@ function isMuseSparkModel(model: string): boolean {
8181
return /^muse-spark/i.test(model.trim());
8282
}
8383

84-
// grok-4.6 accepts xhigh — the same ladder as CODEX_EFFORTS above;
84+
// grok-4.6 and grok-4.7 accept xhigh — the same ladder as CODEX_EFFORTS above;
8585
// grok-4.5 and composer stay on the unknown-model subset.
8686
const GROK_46_EFFORTS: readonly ReasoningEffort[] = CODEX_EFFORTS;
87-
const GROK_46_MODELS: readonly string[] = ["grok-4.6"];
87+
const GROK_46_MODELS: readonly string[] = ["grok-4.6", "grok-4.7"];
8888

8989
// GPT-6 Astra accepts low through max on both the OpenAI API and Codex surfaces.
9090
// Not ultra (gpt-5.6 Codex-only), not minimal, not none.

‎src/subagent/provider-family.test.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ describe("detectModelFamily", () => {
131131
expect(
132132
detectModelFamily({ providerName: "xai/default", model: "grok-4.6" }),
133133
).toBe("grok");
134+
expect(
135+
detectModelFamily({ providerName: "xai/default", model: "grok-4.7" }),
136+
).toBe("grok");
134137
expect(
135138
detectModelFamily({ providerName: "moonshot", model: "kimi-k2" }),
136139
).toBe("kimi");

0 commit comments

Comments
 (0)