feat(xai): prefilled OAuth device link, SuperGrok login label, trimmed model list (#6734)
- Use verification_uri_complete from the xAI device-code response so the login link opens with the user code prefilled (https-validated) - Add OAuthAuth.loginLabel and show "Sign in with SuperGrok or X Premium" in the xAI auth-type selector (threaded through lazyOAuth) - Remove grok-3, grok-3-fast, grok-4.20 variants and grok-code-fast-1 from the built-in xAI catalog and default to grok-4.5 Co-authored-by: Jaaneek <Jaaneek@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
c2c32febb0
commit
a01baaaea7
@@ -31,7 +31,7 @@ export function envApiKeyAuth(name: string, envVars: readonly string[]): ApiKeyA
|
||||
* of bundles by loading through a bundler-opaque dynamic import (variable
|
||||
* specifier, see the bedrock lazy wrapper).
|
||||
*/
|
||||
export function lazyOAuth(input: { name: string; load: () => Promise<OAuthAuth> }): OAuthAuth {
|
||||
export function lazyOAuth(input: { name: string; loginLabel?: string; load: () => Promise<OAuthAuth> }): OAuthAuth {
|
||||
let promise: Promise<OAuthAuth> | undefined;
|
||||
const loaded = () => {
|
||||
promise ??= input.load();
|
||||
@@ -39,6 +39,7 @@ export function lazyOAuth(input: { name: string; load: () => Promise<OAuthAuth>
|
||||
};
|
||||
return {
|
||||
name: input.name,
|
||||
loginLabel: input.loginLabel,
|
||||
login: async (interaction) => (await loaded()).login(interaction),
|
||||
refresh: async (credential) => (await loaded()).refresh(credential),
|
||||
toAuth: async (credential) => (await loaded()).toAuth(credential),
|
||||
|
||||
@@ -25,6 +25,7 @@ type XaiDeviceCode = {
|
||||
deviceCode: string;
|
||||
userCode: string;
|
||||
verificationUri: string;
|
||||
verificationUriComplete?: string;
|
||||
intervalSeconds?: number;
|
||||
expiresInSeconds: number;
|
||||
};
|
||||
@@ -110,10 +111,15 @@ function parseDeviceCode(body: JsonObject): XaiDeviceCode {
|
||||
const interval = body.interval;
|
||||
const intervalSeconds =
|
||||
typeof interval === "number" && Number.isFinite(interval) && interval > 0 ? interval : undefined;
|
||||
const verificationUriComplete =
|
||||
typeof body.verification_uri_complete === "string" && body.verification_uri_complete.length > 0
|
||||
? validateVerificationUri(body.verification_uri_complete)
|
||||
: undefined;
|
||||
return {
|
||||
deviceCode: requiredString(body, "device_code"),
|
||||
userCode: requiredString(body, "user_code"),
|
||||
verificationUri: validateVerificationUri(requiredString(body, "verification_uri")),
|
||||
verificationUriComplete,
|
||||
intervalSeconds,
|
||||
expiresInSeconds: positiveNumber(body, "expires_in"),
|
||||
};
|
||||
@@ -197,7 +203,7 @@ async function loginXai(interaction: AuthInteraction): Promise<OAuthCredential>
|
||||
interaction.notify({
|
||||
type: "device_code",
|
||||
userCode: device.userCode,
|
||||
verificationUri: device.verificationUri,
|
||||
verificationUri: device.verificationUriComplete ?? device.verificationUri,
|
||||
intervalSeconds: device.intervalSeconds,
|
||||
expiresInSeconds: device.expiresInSeconds,
|
||||
});
|
||||
@@ -222,6 +228,7 @@ async function refreshXaiToken(refreshToken: string, signal?: AbortSignal): Prom
|
||||
|
||||
export const xaiOAuth: OAuthAuth = {
|
||||
name: "xAI (Grok/X subscription)",
|
||||
loginLabel: "Sign in with SuperGrok or X Premium",
|
||||
login: loginXai,
|
||||
refresh: (credential, signal) => refreshXaiToken(credential.refresh, signal),
|
||||
|
||||
|
||||
@@ -190,6 +190,9 @@ export interface OAuthAuth {
|
||||
/** Display name, e.g. "Anthropic (Claude Pro/Max)". */
|
||||
name: string;
|
||||
|
||||
/** Selector label for the subscription login option, e.g. "Sign in with SuperGrok or X Premium". */
|
||||
loginLabel?: string;
|
||||
|
||||
login(interaction: AuthInteraction): Promise<OAuthCredential>;
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,78 +4,6 @@
|
||||
import type { Model } from "../types.ts";
|
||||
|
||||
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": {
|
||||
id: "grok-4.3",
|
||||
name: "Grok 4.3",
|
||||
@@ -131,22 +59,4 @@ export const XAI_MODELS = {
|
||||
contextWindow: 256000,
|
||||
maxTokens: 256000,
|
||||
} 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;
|
||||
|
||||
@@ -12,7 +12,11 @@ export function xaiProvider(): Provider<"openai-completions" | "openai-responses
|
||||
baseUrl: "https://api.x.ai/v1",
|
||||
auth: {
|
||||
apiKey: envApiKeyAuth("xAI API key", ["XAI_API_KEY"]),
|
||||
oauth: lazyOAuth({ name: "xAI (Grok/X subscription)", load: loadXaiOAuth }),
|
||||
oauth: lazyOAuth({
|
||||
name: "xAI (Grok/X subscription)",
|
||||
loginLabel: "Sign in with SuperGrok or X Premium",
|
||||
load: loadXaiOAuth,
|
||||
}),
|
||||
},
|
||||
models: Object.values(XAI_MODELS),
|
||||
api: {
|
||||
|
||||
Reference in New Issue
Block a user