@arnilo/prism-provider-xai 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ ## [0.2.8] - 2026-08-19
4
+
5
+ ### Added
6
+
7
+ - Initial `@arnilo/prism-provider-xai` (plan 029 Task 4): Chat Completions at `https://api.x.ai/v1`, featured `grok-4.6` / `grok-4.3` / `grok-build-0.1`, sanitized `x-grok-conv-id`, reasoning replay, SuperGrok RFC 8628 device-code OAuth, caller-gated `listXaiModels`.
8
+
9
+ ## [0.1.0] - 2026-08-09
10
+
11
+ ### Changed
12
+ - Released with exact 0.1.0 graph.
13
+
14
+ ## [0.0.28] - 2026-08-08
15
+
16
+ ### Changed
17
+ - Released with exact 0.0.28 graph.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Prism contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # @arnilo/prism-provider-xai
2
+
3
+ xAI Grok Chat Completions provider for Prism. API key **or** SuperGrok / X Premium OAuth.
4
+
5
+ ```ts
6
+ import { createXaiOAuthProvider, createXaiProviderPackage } from "@arnilo/prism-provider-xai";
7
+ import { refreshOAuthCredential } from "@arnilo/prism";
8
+
9
+ api.registerProviderPackage(createXaiProviderPackage({ apiKey: "fake-xai-key" }));
10
+
11
+ const oauth = createXaiOAuthProvider();
12
+ const creds = await oauth.login({
13
+ onDeviceCode: ({ userCode, verificationUri }) => {
14
+ console.log(`Open ${verificationUri} and enter ${userCode}`);
15
+ },
16
+ });
17
+ await store.set("xai", creds);
18
+
19
+ api.registerProviderPackage(
20
+ createXaiProviderPackage({
21
+ apiKey: async () => {
22
+ const current = await store.get("xai");
23
+ return (await refreshOAuthCredential({ provider: oauth, credentials: current, store })).access;
24
+ },
25
+ }),
26
+ );
27
+ ```
28
+
29
+ Default OAuth client id `b1a00492-073a-47ea-816f-4c329264a828` is the published Grok CLI public client, not a secret. Hosts may override `clientId`. No PKCE loopback. No `~/.grok` scan.
30
+
31
+ Cache: sanitized `x-grok-conv-id` from `cache.key ?? cacheKey ?? sessionId`. Thinking on reasoning models is replayed as `reasoning_content`.
@@ -0,0 +1,6 @@
1
+ import type { ProviderRequest } from "@arnilo/prism";
2
+ /** Clamp for `x-grok-conv-id` (session/customer id, never a credential). */
3
+ export declare const XAI_CONV_ID_MAX_LENGTH = 128;
4
+ export declare function xaiCacheEnabled(request: ProviderRequest): boolean;
5
+ /** Sticky conversation id for xAI prefix cache routing. */
6
+ export declare function xGrokConvId(request: ProviderRequest): string | undefined;
package/dist/cache.js ADDED
@@ -0,0 +1,19 @@
1
+ import { sanitizeCacheKey } from "@arnilo/prism";
2
+ /** Clamp for `x-grok-conv-id` (session/customer id, never a credential). */
3
+ export const XAI_CONV_ID_MAX_LENGTH = 128;
4
+ export function xaiCacheEnabled(request) {
5
+ if (request.options?.cacheRetention === "none")
6
+ return false;
7
+ if (request.options?.cache?.mode === "off")
8
+ return false;
9
+ if (request.model.cache?.kind === "none")
10
+ return false;
11
+ return true;
12
+ }
13
+ /** Sticky conversation id for xAI prefix cache routing. */
14
+ export function xGrokConvId(request) {
15
+ if (!xaiCacheEnabled(request))
16
+ return undefined;
17
+ return sanitizeCacheKey(request.options?.cache?.key ?? request.options?.cacheKey ?? request.options?.sessionId, XAI_CONV_ID_MAX_LENGTH);
18
+ }
19
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1,16 @@
1
+ import { type CredentialValueSource, type ModelConfig, type ProviderPackage } from "@arnilo/prism";
2
+ import { type XaiOAuthOptions } from "./oauth.js";
3
+ export interface XaiProviderPackageOptions {
4
+ readonly apiKey?: CredentialValueSource;
5
+ readonly fetch?: typeof fetch;
6
+ readonly baseUrl?: string;
7
+ readonly id?: string;
8
+ readonly models?: readonly ModelConfig[];
9
+ readonly oauth?: XaiOAuthOptions;
10
+ }
11
+ export declare function createXaiProviderPackage(options?: XaiProviderPackageOptions): ProviderPackage;
12
+ export { XAI_CONV_ID_MAX_LENGTH, xaiCacheEnabled, xGrokConvId } from "./cache.js";
13
+ export { defineXaiModel, type ListXaiModelsOptions, listXaiModels, mapXaiModel, XAI_DEFAULT_BASE_URL, type XaiModelConfig, type XaiModelEntry, xaiModels, } from "./models.js";
14
+ export { createXaiOAuthProvider, parseXaiTokenCredentials, XAI_DEFAULT_CLIENT_ID, XAI_DEFAULT_DEVICE_CODE_URL, XAI_DEFAULT_REFERRER, XAI_DEFAULT_REVOKE_URL, XAI_DEFAULT_SCOPE, XAI_DEFAULT_TOKEN_URL, XAI_REFRESH_SKEW_MS, type XaiOAuthOptions, } from "./oauth.js";
15
+ export { createXaiProvider, toXaiMessage, type XaiProviderOptions, xaiBody, xaiEvents } from "./provider.js";
16
+ export { xaiReplayThinking } from "./thinking.js";
package/dist/index.js ADDED
@@ -0,0 +1,29 @@
1
+ import { defineProviderPackage } from "@arnilo/prism";
2
+ import { xaiModels } from "./models.js";
3
+ import { createXaiOAuthProvider } from "./oauth.js";
4
+ import { createXaiProvider } from "./provider.js";
5
+ export function createXaiProviderPackage(options = {}) {
6
+ const providerId = options.id ?? "xai";
7
+ return defineProviderPackage({
8
+ name: "@arnilo/prism-provider-xai",
9
+ description: "xAI (Grok) provider package for Prism.",
10
+ docs: { links: ["docs/providers/xai.md"] },
11
+ setup(api) {
12
+ api.registerProvider(createXaiProvider(options));
13
+ for (const model of options.models ?? xaiModels)
14
+ api.registerModel({ ...model, provider: providerId });
15
+ api.registerAuthMethod({ kind: "api_key", provider: providerId, credentialName: "apiKey" });
16
+ api.registerAuthMethod({
17
+ kind: "oauth",
18
+ provider: providerId,
19
+ oauth: createXaiOAuthProvider({ fetch: options.fetch, ...options.oauth }),
20
+ });
21
+ },
22
+ });
23
+ }
24
+ export { XAI_CONV_ID_MAX_LENGTH, xaiCacheEnabled, xGrokConvId } from "./cache.js";
25
+ export { defineXaiModel, listXaiModels, mapXaiModel, XAI_DEFAULT_BASE_URL, xaiModels, } from "./models.js";
26
+ export { createXaiOAuthProvider, parseXaiTokenCredentials, XAI_DEFAULT_CLIENT_ID, XAI_DEFAULT_DEVICE_CODE_URL, XAI_DEFAULT_REFERRER, XAI_DEFAULT_REVOKE_URL, XAI_DEFAULT_SCOPE, XAI_DEFAULT_TOKEN_URL, XAI_REFRESH_SKEW_MS, } from "./oauth.js";
27
+ export { createXaiProvider, toXaiMessage, xaiBody, xaiEvents } from "./provider.js";
28
+ export { xaiReplayThinking } from "./thinking.js";
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,26 @@
1
+ import { type CredentialValueSource, type ModelConfig } from "@arnilo/prism";
2
+ export declare const XAI_DEFAULT_BASE_URL = "https://api.x.ai/v1";
3
+ export interface XaiModelConfig extends Omit<ModelConfig, "provider"> {
4
+ readonly provider?: "xai";
5
+ }
6
+ export interface ListXaiModelsOptions {
7
+ readonly apiKey?: CredentialValueSource;
8
+ readonly fetch?: typeof fetch;
9
+ readonly baseUrl?: string;
10
+ readonly signal?: AbortSignal;
11
+ readonly headers?: Readonly<Record<string, string>>;
12
+ readonly provider?: string;
13
+ }
14
+ export interface XaiModelEntry {
15
+ readonly id: string;
16
+ readonly object?: string;
17
+ readonly created?: number;
18
+ readonly owned_by?: string;
19
+ }
20
+ export declare function defineXaiModel(config: XaiModelConfig): ModelConfig;
21
+ /** Caller-gated `GET {base}/models`. Never invoked by `createXaiProviderPackage`. */
22
+ export declare function listXaiModels(options?: ListXaiModelsOptions): Promise<ModelConfig[]>;
23
+ export declare function mapXaiModel(entry: XaiModelEntry, options?: {
24
+ readonly provider?: string;
25
+ }): ModelConfig;
26
+ export declare const xaiModels: ModelConfig[];
package/dist/models.js ADDED
@@ -0,0 +1,75 @@
1
+ import { redactSecrets, resolveCredentialValue } from "@arnilo/prism";
2
+ import { readBoundedResponseJson, readBoundedResponseText } from "@arnilo/prism/providers/transport";
3
+ export const XAI_DEFAULT_BASE_URL = "https://api.x.ai/v1";
4
+ const FEATURED = {
5
+ "grok-4.6": {
6
+ displayName: "Grok 4.6",
7
+ limits: { contextWindow: 500_000, maxOutputTokens: 500_000 },
8
+ cost: { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 },
9
+ },
10
+ "grok-4.3": {
11
+ displayName: "Grok 4.3",
12
+ limits: { contextWindow: 1_000_000, maxOutputTokens: 30_000 },
13
+ cost: { input: 1.25, output: 2.5, cacheRead: 0.2, cacheWrite: 0 },
14
+ },
15
+ "grok-build-0.1": {
16
+ displayName: "Grok Build 0.1",
17
+ limits: { contextWindow: 256_000, maxOutputTokens: 256_000 },
18
+ cost: { input: 1, output: 2, cacheRead: 0.2, cacheWrite: 0 },
19
+ },
20
+ };
21
+ export function defineXaiModel(config) {
22
+ return {
23
+ ...config,
24
+ provider: "xai",
25
+ capabilities: {
26
+ input: ["text", "image"],
27
+ output: ["text"],
28
+ reasoning: true,
29
+ tools: true,
30
+ streaming: true,
31
+ structuredOutput: "json_schema",
32
+ ...config.capabilities,
33
+ },
34
+ cache: config.cache ?? { kind: "implicit" },
35
+ };
36
+ }
37
+ /** Caller-gated `GET {base}/models`. Never invoked by `createXaiProviderPackage`. */
38
+ export async function listXaiModels(options = {}) {
39
+ const provider = options.provider ?? "xai";
40
+ const baseUrl = (options.baseUrl ?? XAI_DEFAULT_BASE_URL).replace(/\/+$/, "");
41
+ const token = await resolveCredentialValue(options.apiKey, { provider, name: "apiKey" });
42
+ const response = await (options.fetch ?? fetch)(`${baseUrl}/models`, {
43
+ method: "GET",
44
+ headers: { ...options.headers, ...(token ? { authorization: `Bearer ${token}` } : {}) },
45
+ signal: options.signal,
46
+ });
47
+ if (!response.ok) {
48
+ const body = await readBoundedResponseText(response, { secrets: [token] });
49
+ throw new Error(`xAI model discovery failed: ${response.status} ${redactSecrets(body, [token])}`);
50
+ }
51
+ const payload = await readBoundedResponseJson(response);
52
+ if (!Array.isArray(payload.data))
53
+ throw new Error("xAI model discovery response missing data array");
54
+ return payload.data.map((entry) => mapXaiModel(entry, { provider }));
55
+ }
56
+ export function mapXaiModel(entry, options = {}) {
57
+ if (!entry || typeof entry.id !== "string" || entry.id.length === 0) {
58
+ throw new Error("xAI model entry missing id");
59
+ }
60
+ const known = FEATURED[entry.id];
61
+ return defineXaiModel({
62
+ provider: options.provider ?? "xai",
63
+ model: entry.id,
64
+ displayName: known?.displayName ?? entry.id,
65
+ limits: known?.limits ?? { contextWindow: 131_072, maxOutputTokens: 8_192 },
66
+ cost: known?.cost,
67
+ cache: { kind: "implicit" },
68
+ compat: { xai: cleanJson({ owned_by: entry.owned_by, created: entry.created }) },
69
+ });
70
+ }
71
+ export const xaiModels = ["grok-4.6", "grok-4.3", "grok-build-0.1"].map((id) => defineXaiModel({ model: id, ...FEATURED[id] }));
72
+ function cleanJson(value) {
73
+ return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined));
74
+ }
75
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1,21 @@
1
+ import type { OAuthCredentials, OAuthProvider, OAuthTokenSuccessPayload } from "@arnilo/prism";
2
+ export declare const XAI_DEFAULT_CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828";
3
+ export declare const XAI_DEFAULT_SCOPE = "openid profile email offline_access grok-cli:access api:access";
4
+ export declare const XAI_DEFAULT_DEVICE_CODE_URL = "https://auth.x.ai/oauth2/device/code";
5
+ export declare const XAI_DEFAULT_TOKEN_URL = "https://auth.x.ai/oauth2/token";
6
+ export declare const XAI_DEFAULT_REVOKE_URL = "https://auth.x.ai/oauth2/revoke";
7
+ export declare const XAI_DEFAULT_REFERRER = "prism";
8
+ export declare const XAI_REFRESH_SKEW_MS: number;
9
+ export interface XaiOAuthOptions {
10
+ readonly clientId?: string;
11
+ readonly fetch?: typeof fetch;
12
+ readonly deviceCodeUrl?: string;
13
+ readonly tokenUrl?: string;
14
+ readonly revokeUrl?: string;
15
+ readonly scope?: string;
16
+ readonly referrer?: string;
17
+ readonly now?: () => number;
18
+ readonly sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
19
+ }
20
+ export declare function createXaiOAuthProvider(options?: XaiOAuthOptions): OAuthProvider;
21
+ export declare function parseXaiTokenCredentials(json: OAuthTokenSuccessPayload, previousRefresh?: string, now?: () => number): OAuthCredentials;
package/dist/oauth.js ADDED
@@ -0,0 +1,98 @@
1
+ import { abortableSleep, pollDeviceCodeToken, redactOAuthError, throwIfAborted } from "@arnilo/prism";
2
+ import { readBoundedResponseJson, readBoundedResponseText } from "@arnilo/prism/providers/transport";
3
+ export const XAI_DEFAULT_CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828";
4
+ export const XAI_DEFAULT_SCOPE = "openid profile email offline_access grok-cli:access api:access";
5
+ export const XAI_DEFAULT_DEVICE_CODE_URL = "https://auth.x.ai/oauth2/device/code";
6
+ export const XAI_DEFAULT_TOKEN_URL = "https://auth.x.ai/oauth2/token";
7
+ export const XAI_DEFAULT_REVOKE_URL = "https://auth.x.ai/oauth2/revoke";
8
+ export const XAI_DEFAULT_REFERRER = "prism";
9
+ export const XAI_REFRESH_SKEW_MS = 5 * 60 * 1000;
10
+ const DEFAULT_TOKEN_LIFETIME_SECONDS = 3600;
11
+ export function createXaiOAuthProvider(options = {}) {
12
+ const clientId = options.clientId ?? XAI_DEFAULT_CLIENT_ID;
13
+ const fetchImpl = options.fetch ?? fetch;
14
+ const deviceCodeUrl = options.deviceCodeUrl ?? XAI_DEFAULT_DEVICE_CODE_URL;
15
+ const tokenUrl = options.tokenUrl ?? XAI_DEFAULT_TOKEN_URL;
16
+ const revokeUrl = options.revokeUrl ?? XAI_DEFAULT_REVOKE_URL;
17
+ const scope = options.scope ?? XAI_DEFAULT_SCOPE;
18
+ const referrer = options.referrer ?? XAI_DEFAULT_REFERRER;
19
+ const now = options.now ?? Date.now;
20
+ const sleep = options.sleep ?? abortableSleep;
21
+ return {
22
+ id: "xai",
23
+ async login(callbacks) {
24
+ throwIfAborted(callbacks?.signal);
25
+ if (!callbacks?.onDeviceCode) {
26
+ throw new Error("xAI SuperGrok login requires onDeviceCode");
27
+ }
28
+ return pollDeviceCodeToken({
29
+ fetchImpl,
30
+ deviceCodeUrl,
31
+ tokenUrl,
32
+ clientId,
33
+ scope,
34
+ extraDeviceParams: { referrer },
35
+ bodyEncoding: "form",
36
+ callbacks,
37
+ errorPrefix: "xAI",
38
+ now,
39
+ sleep,
40
+ parseTokenCredentials: (json) => parseXaiTokenCredentials(json, undefined, now),
41
+ });
42
+ },
43
+ async refresh(credentials) {
44
+ if (!credentials.refresh)
45
+ return credentials;
46
+ return exchangeForm(fetchImpl, tokenUrl, { grant_type: "refresh_token", client_id: clientId, refresh_token: credentials.refresh }, [credentials.access, credentials.refresh], (json) => parseXaiTokenCredentials(json, credentials.refresh, now));
47
+ },
48
+ async revoke(credentials) {
49
+ const token = credentials.access ?? credentials.refresh;
50
+ if (!token)
51
+ return;
52
+ const secrets = [credentials.access, credentials.refresh];
53
+ try {
54
+ const response = await fetchImpl(revokeUrl, {
55
+ method: "POST",
56
+ headers: { "content-type": "application/x-www-form-urlencoded" },
57
+ body: new URLSearchParams({
58
+ token,
59
+ client_id: clientId,
60
+ token_type_hint: credentials.access ? "access_token" : "refresh_token",
61
+ }).toString(),
62
+ });
63
+ if (!response.ok)
64
+ await readBoundedResponseText(response, { secrets });
65
+ }
66
+ catch {
67
+ // best-effort; local store delete is the fail-closed boundary
68
+ }
69
+ },
70
+ getCredential(credentials) {
71
+ return credentials.access ? { type: "bearer", value: credentials.access } : undefined;
72
+ },
73
+ };
74
+ }
75
+ export function parseXaiTokenCredentials(json, previousRefresh, now = Date.now) {
76
+ const expiresIn = json.expires_in ?? DEFAULT_TOKEN_LIFETIME_SECONDS;
77
+ return {
78
+ access: json.access_token,
79
+ refresh: json.refresh_token ?? previousRefresh,
80
+ expires: now() + expiresIn * 1_000 - XAI_REFRESH_SKEW_MS,
81
+ };
82
+ }
83
+ async function exchangeForm(fetchImpl, url, body, secrets, parse) {
84
+ const response = await fetchImpl(url, {
85
+ method: "POST",
86
+ headers: { "content-type": "application/x-www-form-urlencoded" },
87
+ body: new URLSearchParams(body).toString(),
88
+ });
89
+ if (!response.ok) {
90
+ const detail = await readBoundedResponseText(response, { secrets });
91
+ throw redactOAuthError(new Error(`xAI token request failed: ${response.status} ${detail}`), secrets);
92
+ }
93
+ const json = await readBoundedResponseJson(response, {
94
+ shape: (value) => typeof value === "object" && value !== null && typeof value.access_token === "string",
95
+ });
96
+ return parse(json);
97
+ }
98
+ //# sourceMappingURL=oauth.js.map
@@ -0,0 +1,14 @@
1
+ import type { AIProvider, JsonObject, Message, ProviderEvent, ProviderRequest } from "@arnilo/prism";
2
+ import { type CredentialValueSource } from "@arnilo/prism";
3
+ import { XAI_DEFAULT_BASE_URL } from "./models.js";
4
+ export { XAI_DEFAULT_BASE_URL };
5
+ export interface XaiProviderOptions {
6
+ readonly id?: string;
7
+ readonly baseUrl?: string;
8
+ readonly apiKey?: CredentialValueSource;
9
+ readonly fetch?: typeof fetch;
10
+ }
11
+ export declare function createXaiProvider(options?: XaiProviderOptions): AIProvider;
12
+ export declare function xaiBody(request: ProviderRequest): JsonObject;
13
+ export declare function xaiEvents(body: ReadableStream<Uint8Array>, signal?: AbortSignal): AsyncIterable<ProviderEvent>;
14
+ export declare function toXaiMessage(message: Message, request: ProviderRequest): JsonObject;
@@ -0,0 +1,63 @@
1
+ import { applyOpenAIChatStructuredOutput, serializeOpenAIChatMessage } from "@arnilo/prism/providers/openai";
2
+ import { buildOpenAIChatBody, createOpenAICompatibleProvider, openAIChatEvents } from "@arnilo/prism/providers/openai-compatible";
3
+ import { xGrokConvId } from "./cache.js";
4
+ import { XAI_DEFAULT_BASE_URL } from "./models.js";
5
+ import { xaiReplayThinking } from "./thinking.js";
6
+ export { XAI_DEFAULT_BASE_URL };
7
+ export function createXaiProvider(options = {}) {
8
+ return createOpenAICompatibleProvider({
9
+ id: options.id ?? "xai",
10
+ baseUrl: (options.baseUrl ?? XAI_DEFAULT_BASE_URL).replace(/\/+$/, ""),
11
+ apiKey: options.apiKey,
12
+ fetch: options.fetch,
13
+ doneUsage: true,
14
+ requestFailedPrefix: "xAI request failed",
15
+ serializeMessage: (message, request) => toXaiMessage(message, request),
16
+ extraHeaders: (request) => {
17
+ const convId = xGrokConvId(request);
18
+ const headers = {};
19
+ if (convId)
20
+ headers["x-grok-conv-id"] = convId;
21
+ return headers;
22
+ },
23
+ transformBody: (body, request) => xaiTransform(body, request),
24
+ });
25
+ }
26
+ export function xaiBody(request) {
27
+ return buildOpenAIChatBody(request, {
28
+ serializeMessage: (message, req) => toXaiMessage(message, req),
29
+ transformBody: (body, req) => xaiTransform(body, req),
30
+ });
31
+ }
32
+ export function xaiEvents(body, signal) {
33
+ return openAIChatEvents(body, { signal, doneUsage: true });
34
+ }
35
+ export function toXaiMessage(message, request) {
36
+ if (!xaiReplayThinking(request)) {
37
+ return serializeOpenAIChatMessage(message, request.model.capabilities ?? {});
38
+ }
39
+ const thinking = message.content.filter((part) => part.type === "thinking").map((part) => part.text);
40
+ const reasoningContent = thinking.length > 0 ? thinking.join("\n") : undefined;
41
+ const withoutThinking = {
42
+ ...message,
43
+ content: message.content.filter((part) => part.type !== "thinking"),
44
+ };
45
+ return clean({
46
+ ...serializeOpenAIChatMessage(withoutThinking, request.model.capabilities ?? {}),
47
+ reasoning_content: reasoningContent,
48
+ });
49
+ }
50
+ function xaiTransform(body, request) {
51
+ const { maxTokens, ...rest } = body;
52
+ const transformed = {
53
+ ...rest,
54
+ max_tokens: maxTokens ?? request.model.limits?.maxOutputTokens,
55
+ ...request.options?.extra,
56
+ };
57
+ applyOpenAIChatStructuredOutput(transformed, request.options?.structuredOutput);
58
+ return clean(transformed);
59
+ }
60
+ function clean(value) {
61
+ return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined));
62
+ }
63
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1,3 @@
1
+ import type { ProviderRequest } from "@arnilo/prism";
2
+ /** Reasoning models must replay prior thinking as `reasoning_content` or the prefix cache breaks. */
3
+ export declare function xaiReplayThinking(request: ProviderRequest): boolean;
@@ -0,0 +1,5 @@
1
+ /** Reasoning models must replay prior thinking as `reasoning_content` or the prefix cache breaks. */
2
+ export function xaiReplayThinking(request) {
3
+ return request.model.capabilities?.reasoning === true;
4
+ }
5
+ //# sourceMappingURL=thinking.js.map
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@arnilo/prism-provider-xai",
3
+ "version": "0.2.9",
4
+ "description": "xAI (Grok) provider package for Prism.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "!dist/__tests__",
17
+ "!dist/**/*.map",
18
+ "README.md",
19
+ "CHANGELOG.md"
20
+ ],
21
+ "scripts": {
22
+ "build": "node ../../scripts/with-build-lock.mjs tsc -p tsconfig.json",
23
+ "typecheck": "tsc -p tsconfig.json --noEmit",
24
+ "test": "node ../../scripts/with-build-lock.mjs node --test dist/__tests__/*.test.js",
25
+ "pack:dry-run": "npm pack --dry-run"
26
+ },
27
+ "peerDependencies": {
28
+ "@arnilo/prism": "0.2.9"
29
+ },
30
+ "devDependencies": {
31
+ "@arnilo/prism": "file:../.."
32
+ },
33
+ "engines": {
34
+ "node": ">=20"
35
+ },
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/ashiqrniloy/prism.git",
40
+ "directory": "packages/provider-xai"
41
+ },
42
+ "bugs": {
43
+ "url": "https://github.com/ashiqrniloy/prism/issues"
44
+ },
45
+ "homepage": "https://github.com/ashiqrniloy/prism/tree/main/packages/provider-xai#readme",
46
+ "keywords": [
47
+ "prism",
48
+ "provider",
49
+ "xai",
50
+ "grok",
51
+ "supergrok",
52
+ "agent",
53
+ "llm"
54
+ ],
55
+ "sideEffects": false,
56
+ "publishConfig": {
57
+ "access": "public"
58
+ }
59
+ }