@warlock.js/ai-xai 5.30.0 → 5.32.0
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 +26 -0
- package/README.md +12 -12
- package/cjs/index.cjs +21 -1
- package/cjs/index.cjs.map +1 -1
- package/esm/config.type.d.mts +15 -7
- package/esm/config.type.d.mts.map +1 -1
- package/esm/known-models.d.mts +5 -6
- package/esm/known-models.d.mts.map +1 -1
- package/esm/sdk.d.mts +1 -3
- package/esm/sdk.d.mts.map +1 -1
- package/esm/sdk.mjs +21 -1
- package/esm/sdk.mjs.map +1 -1
- package/llms-full.txt +65 -24
- package/llms.txt +1 -1
- package/package.json +4 -4
- package/skills/setup-xai/SKILL.md +65 -24
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,31 @@ All notable changes to `@warlock.js/ai-xai` are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
|
|
6
6
|
|
|
7
|
+
## 5.32.0 - 2026-10-18
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Pin the package development compiler to TypeScript 7.0.2 and use explicit Node types and source roots with supported module resolution.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Document and test explicit rejection of native `web_search` / `x_search` on the current Chat Completions transport, with guidance to use xAI’s Responses API before any request is sent.
|
|
16
|
+
|
|
17
|
+
## 5.31.0 - 2026-10-18
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- An adapter contract test verifies that aborting `signal` rejects `complete()` and `stream()` on the model and cancels the HTTP request.
|
|
22
|
+
- `XaiModelConfig.promptCacheKey` is sent as `prompt_cache_key` (xAI routes it to `x-grok-conv-id`), so requests sharing a prefix reuse the same cache.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- Chat calls inherit `providerOptions.openai.body` from the OpenAI adapter, including its protected fields and one-level plain-object merge. Use only this provider's accepted fields when sharing fallback options. Native `countTokens` remains absent; `sdk.count(text)` is an offline estimate.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- The provider-body and token-estimate guidance renders as prose instead of being swallowed by a stray code fence.
|
|
31
|
+
|
|
7
32
|
## 5.30.0 - 2026-10-16
|
|
8
33
|
|
|
9
34
|
### Changed
|
|
@@ -81,6 +106,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
81
106
|
### Changed
|
|
82
107
|
|
|
83
108
|
- Lockstep release maintenance and dependency refresh.
|
|
109
|
+
|
|
84
110
|
## 5.20.0 - 2026-09-24
|
|
85
111
|
|
|
86
112
|
### Changed
|
package/README.md
CHANGED
|
@@ -51,22 +51,22 @@ XaiModelConfig {
|
|
|
51
51
|
|
|
52
52
|
Capabilities are inferred from the Grok model **name** (via `inferVisionCapability` / `inferReasoningCapability`, matched as a prefix so dated / `-latest` / `-fast` / `-beta` variants are covered) and injected as explicit flags before delegating — an explicit value always wins.
|
|
53
53
|
|
|
54
|
-
| Model | `vision` | `reasoning`
|
|
55
|
-
| --------------- | -------- |
|
|
56
|
-
| `grok-4` | true | true (reasoning-first)
|
|
57
|
-
| `grok-3` | false | false
|
|
54
|
+
| Model | `vision` | `reasoning` |
|
|
55
|
+
| --------------- | -------- | -------------------------- |
|
|
56
|
+
| `grok-4` | true | true (reasoning-first) |
|
|
57
|
+
| `grok-3` | false | false |
|
|
58
58
|
| `grok-3-mini` | false | true (the "think" variant) |
|
|
59
|
-
| `grok-2-vision` | true | false
|
|
60
|
-
| `grok-2` | false | false
|
|
59
|
+
| `grok-2-vision` | true | false |
|
|
60
|
+
| `grok-2` | false | false |
|
|
61
61
|
|
|
62
62
|
- `structuredOutput` / `promptCaching` and the image / PDF / audio wire mapping all come from the wrapped OpenAI adapter unchanged.
|
|
63
63
|
- `XAI_CHAT_MODELS`, `XAI_VISION_MODEL_PREFIXES`, and `XAI_REASONING_MODEL_PREFIXES` are exported for menus, validation, and docs.
|
|
64
64
|
|
|
65
65
|
```ts
|
|
66
|
-
xai.model({ name: "grok-4" });
|
|
67
|
-
xai.model({ name: "grok-3-mini" });
|
|
68
|
-
xai.model({ name: "grok-2-vision" });
|
|
69
|
-
xai.model({ name: "grok-3", vision: true });
|
|
66
|
+
xai.model({ name: "grok-4" }); // vision + reasoning auto-true
|
|
67
|
+
xai.model({ name: "grok-3-mini" }); // reasoning auto-true, vision false
|
|
68
|
+
xai.model({ name: "grok-2-vision" }); // vision auto-true
|
|
69
|
+
xai.model({ name: "grok-3", vision: true }); // explicit capability override
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
> Model availability changes over time — pass any current Grok id through `.model({ name })`; the prefix inference covers dated / `-latest` variants. Don't assume a model exists; check xAI's docs.
|
|
@@ -74,8 +74,8 @@ xai.model({ name: "grok-3", vision: true }); // explicit capability override
|
|
|
74
74
|
## Reasoning effort
|
|
75
75
|
|
|
76
76
|
```ts
|
|
77
|
-
const model = xai.model({ name: "grok-4" });
|
|
78
|
-
await model.complete(messages, { reasoning: { effort: "high" } });
|
|
77
|
+
const model = xai.model({ name: "grok-4" }); // reasoning auto-true
|
|
78
|
+
await model.complete(messages, { reasoning: { effort: "high" } }); // → reasoning_effort: "high"
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
`reasoning.effort` (`"low" | "medium" | "high"`) maps verbatim to the OpenAI-compatible `reasoning_effort` param and is dropped for a non-reasoning model (e.g. `grok-3`).
|
package/cjs/index.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
let _warlock_js_ai = require("@warlock.js/ai");
|
|
2
3
|
let _warlock_js_ai_openai = require("@warlock.js/ai-openai");
|
|
3
4
|
|
|
4
5
|
//#region ../../packages/ai-xai/src/known-models.ts
|
|
@@ -178,11 +179,26 @@ var XaiSDK = class {
|
|
|
178
179
|
* xai.model({ name: "grok-3-mini" }); // reasoning auto-true, vision false
|
|
179
180
|
*/
|
|
180
181
|
model(config) {
|
|
181
|
-
|
|
182
|
+
const model = this.openai.model({
|
|
182
183
|
...config,
|
|
183
184
|
vision: config.vision ?? inferVisionCapability(config.name),
|
|
184
185
|
reasoning: config.reasoning ?? inferReasoningCapability(config.name)
|
|
185
186
|
});
|
|
187
|
+
return {
|
|
188
|
+
name: model.name,
|
|
189
|
+
provider: model.provider,
|
|
190
|
+
capabilities: model.capabilities,
|
|
191
|
+
...model.pricing ? { pricing: model.pricing } : {},
|
|
192
|
+
async complete(messages, options) {
|
|
193
|
+
rejectNativeSearch(model.provider, options);
|
|
194
|
+
return model.complete(messages, options);
|
|
195
|
+
},
|
|
196
|
+
async *stream(messages, options) {
|
|
197
|
+
rejectNativeSearch(model.provider, options);
|
|
198
|
+
yield* model.stream(messages, options);
|
|
199
|
+
},
|
|
200
|
+
...model.countTokens ? { countTokens: model.countTokens.bind(model) } : {}
|
|
201
|
+
};
|
|
186
202
|
}
|
|
187
203
|
/**
|
|
188
204
|
* Rough token-count estimate. Delegates straight to the wrapped
|
|
@@ -214,6 +230,10 @@ var XaiSDK = class {
|
|
|
214
230
|
return this.openai.image(config);
|
|
215
231
|
}
|
|
216
232
|
};
|
|
233
|
+
/** A provider label does not change the underlying Chat Completions transport. */
|
|
234
|
+
function rejectNativeSearch(provider, options) {
|
|
235
|
+
if ([...options?.providerTools ?? [], ...(options?.tools ?? []).filter(_warlock_js_ai.isProviderTool)].some((entry) => entry.provider === provider && (entry.definition.type === "web_search" || entry.definition.type === "x_search"))) throw new _warlock_js_ai.InvalidRequestError("xAI native web_search / x_search requires POST /v1/responses. XaiSDK currently supports Chat Completions only; use xAI's Responses API with the vendor SDK for native search.");
|
|
236
|
+
}
|
|
217
237
|
|
|
218
238
|
//#endregion
|
|
219
239
|
exports.XAI_CHAT_MODELS = XAI_CHAT_MODELS;
|
package/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["OpenAISDK"],"sources":["../../../../../../../packages/ai-xai/src/known-models.ts","../../../../../../../packages/ai-xai/src/sdk.ts"],"sourcesContent":["/**\n * Capability inference for xAI Grok model ids.\n *\n * xAI speaks the OpenAI Chat Completions protocol, so the wire-level\n * adapter is `OpenAISDK`. But Grok model names (`grok-4`,\n * `grok-2-vision`, …) don't match OpenAI's `gpt-*` / `o*` prefixes, so\n * OpenAI's own inference lists would mis-classify every Grok model as\n * non-vision / non-reasoning. This module supplies xAI's OWN name lists\n * and the `XaiSDK` wrapper injects the resulting capability flags into\n * each `OpenAIModelConfig` before delegating, so the right capabilities\n * are set even though the names aren't OpenAI names.\n *\n * All lists are matched as a prefix so dated / `-latest` / `-fast`\n * variants (`grok-4-0709`, `grok-2-vision-latest`,\n * `grok-3-mini-beta`) are covered without enumerating every release\n * tag. Devs can always override per-model via\n * `xai.model({ name, vision: true | false, reasoning: true | false })`\n * — explicit config wins over inference in either direction.\n */\n\n/**\n * Model-name prefixes for Grok families that accept image input\n * (vision) on the OpenAI-compatible Chat Completions endpoint.\n *\n * - `grok-4` is natively multimodal (text + image input).\n * - `grok-2-vision` is the dedicated image-understanding Grok 2 model.\n *\n * Text-only families (`grok-3`, `grok-3-mini`, the base `grok-2`\n * text model) are intentionally excluded so passing an image\n * attachment to them surfaces a clear, agent-side capability error\n * rather than an opaque xAI 400.\n */\nexport const XAI_VISION_MODEL_PREFIXES = [\"grok-4\", \"grok-2-vision\"] as const;\n\n/**\n * Model-name prefixes for Grok families that expose internal reasoning\n * and accept reasoning controls (e.g. `reasoning_effort`) on the\n * OpenAI-compatible Chat Completions endpoint.\n *\n * - `grok-4` is a reasoning-first model (it always reasons).\n * - `grok-3-mini` is the \"think\" variant of Grok 3 and reasons; the\n * full-size `grok-3` does not, so it is deliberately NOT covered by\n * the `grok-3-mini` prefix.\n */\nexport const XAI_REASONING_MODEL_PREFIXES = [\"grok-4\", \"grok-3-mini\"] as const;\n\n/**\n * A convenience list of the current public Grok chat model ids, handy\n * for menus, validation, and docs. Not exhaustive of every dated alias\n * xAI publishes — pass any id through `xai.model({ name })`; the prefix\n * inference above handles dated / `-latest` variants.\n *\n * @example\n * XAI_CHAT_MODELS.includes(\"grok-4\"); // → true\n */\nexport const XAI_CHAT_MODELS = [\n \"grok-4\",\n \"grok-3\",\n \"grok-3-mini\",\n \"grok-2-vision\",\n \"grok-2\",\n] as const;\n\n/**\n * Infer whether a given Grok model id supports vision based on xAI's\n * known-prefix list. Unknown ids default to `false` so that passing an\n * image attachment to an unsupported model surfaces a clear,\n * agent-side capability error instead of an opaque xAI 400.\n *\n * @example\n * inferVisionCapability(\"grok-4\"); // → true\n * inferVisionCapability(\"grok-2-vision-latest\"); // → true\n * inferVisionCapability(\"grok-3\"); // → false\n * inferVisionCapability(\"grok-3-mini\"); // → false\n */\nexport function inferVisionCapability(modelId: string): boolean {\n const normalized = modelId.toLowerCase();\n\n return XAI_VISION_MODEL_PREFIXES.some((prefix) => normalized.startsWith(prefix));\n}\n\n/**\n * Infer whether a given Grok model id is a reasoning model based on\n * xAI's known-prefix list. Unknown ids default to `false` so the\n * adapter never forwards an unsupported reasoning param to a\n * non-reasoning model.\n *\n * @example\n * inferReasoningCapability(\"grok-4\"); // → true\n * inferReasoningCapability(\"grok-3-mini\"); // → true\n * inferReasoningCapability(\"grok-3\"); // → false\n * inferReasoningCapability(\"grok-2-vision\"); // → false\n */\nexport function inferReasoningCapability(modelId: string): boolean {\n const normalized = modelId.toLowerCase();\n\n return XAI_REASONING_MODEL_PREFIXES.some((prefix) => normalized.startsWith(prefix));\n}\n","import type {\n EmbedderContract,\n ImageModelContract,\n ModelContract,\n ModelPricing,\n SDKAdapterContract,\n} from \"@warlock.js/ai\";\nimport { OpenAISDK } from \"@warlock.js/ai-openai\";\nimport type {\n XaiEmbedderConfig,\n XaiImageConfig,\n XaiModelConfig,\n XaiSDKConfig,\n} from \"./config.type\";\nimport { inferReasoningCapability, inferVisionCapability } from \"./known-models\";\n\n/**\n * The xAI OpenAI-compatible base URL. xAI exposes Chat Completions at\n * `POST /v1/chat/completions` on this host, so the whole adapter rides\n * on the OpenAI wire protocol.\n */\nconst XAI_BASE_URL = \"https://api.x.ai/v1\";\n\n/**\n * The default `provider` label stamped on every model this SDK\n * produces. Surfaces on `ModelContract.provider`, `AgentReport.model`,\n * logs, and any provider-aware middleware.\n */\nconst XAI_PROVIDER = \"xai\";\n\n/**\n * xAI Grok-backed implementation of `SDKAdapterContract`.\n *\n * **Role.** The package entry point for xAI's Grok models. xAI speaks\n * the OpenAI Chat Completions protocol, so `XaiSDK` is a *thin wrapper*\n * over the already-battle-tested {@link OpenAISDK} from\n * `@warlock.js/ai-openai` — NOT a reimplementation. It constructs one\n * internal `OpenAISDK` pointed at xAI's `baseURL` and labeled\n * `provider: \"xai\"`, then delegates `model()` / `embedder()` /\n * `image()` / `count()` to it. Construct one SDK per account and reuse\n * it everywhere.\n *\n * **Responsibility.**\n * - Owns: the xAI defaults (`baseURL` → `https://api.x.ai/v1`,\n * `provider` → `\"xai\"`) and this provider's OWN capability inference.\n * Grok model names (`grok-4`, `grok-2-vision`, …) don't match\n * OpenAI's `gpt-*` / `o*` prefixes, so before delegating `model()`\n * the wrapper injects the `vision` / `reasoning` flags inferred from\n * xAI's name lists (see `known-models.ts`). Because explicit config\n * wins over OpenAI's inference inside `OpenAIModel`, the produced\n * `ModelContract` carries the correct Grok capabilities.\n * - Does NOT own: the wire protocol, request/response mapping,\n * streaming, tool-call accumulation, error wrapping, or pricing\n * resolution — all of that is the wrapped `OpenAISDK`'s job and is\n * reused verbatim.\n *\n * Modeled as a class (see §4.2 of code-style.md — \"long-lived state\n * across many calls\"): it holds one live `OpenAISDK` (which in turn\n * holds one live `OpenAI` client), fronted by FP usage like the other\n * adapters.\n *\n * @example\n * const xai = new XaiSDK({ apiKey: process.env.XAI_API_KEY! });\n * const model = xai.model({ name: \"grok-4\", temperature: 0.7 });\n * const myAgent = ai.agent({ model });\n *\n * @example\n * // Compose into an `ai.xai` namespace for ergonomic agent wiring.\n * const ai = { agent, tool, systemPrompt, xai: new XaiSDK({ apiKey }) };\n * const fast = ai.agent({ model: ai.xai.model({ name: \"grok-3-mini\" }) });\n */\nexport class XaiSDK implements SDKAdapterContract {\n /**\n * The wrapped OpenAI-compatible adapter doing the actual wire work.\n * Constructed once with xAI's `baseURL` + `provider` and the caller's\n * `apiKey` / client options, then reused for every produced model,\n * embedder, and image model.\n */\n private readonly openai: OpenAISDK;\n\n /**\n * Optional SDK-level pricing registry, kept so `model()` can resolve\n * a per-model entry while still applying this provider's default\n * capability inference. The wrapped `OpenAISDK` also resolves\n * pricing, but we surface it here for parity and to keep the default\n * baseURL/provider injection in one place.\n */\n private readonly pricing?: Record<string, ModelPricing>;\n\n public constructor(config: XaiSDKConfig) {\n const { baseURL, provider, ...rest } = config;\n\n // Inject xAI's defaults — `baseURL` → the xAI OpenAI-compatible\n // endpoint, `provider` → \"xai\" — while still letting the caller\n // override either (e.g. a corporate proxy or a relabeled gateway).\n this.openai = new OpenAISDK({\n ...rest,\n baseURL: baseURL ?? XAI_BASE_URL,\n provider: provider ?? XAI_PROVIDER,\n });\n\n this.pricing = config.pricing;\n }\n\n /**\n * Build a `ModelContract` for a Grok model. Delegates to the wrapped\n * `OpenAISDK.model()` after injecting this provider's OWN capability\n * inference: `vision` and `reasoning` are resolved from xAI's\n * name-prefix lists (see `known-models.ts`) unless the caller set them\n * explicitly. Because explicit config wins over OpenAI's inference\n * inside `OpenAIModel`, the returned model self-identifies as\n * `provider: \"xai\"` and carries Grok's real capabilities even though\n * the model name isn't an OpenAI name.\n *\n * Pricing resolution is left to the wrapped adapter: per-model\n * `config.pricing` wins, otherwise the SDK-level registry entry keyed\n * by `config.name`, otherwise `undefined` (no cost computed).\n *\n * @example\n * xai.model({ name: \"grok-4\" }); // vision + reasoning auto-true\n * xai.model({ name: \"grok-3-mini\" }); // reasoning auto-true, vision false\n */\n public model(config: XaiModelConfig): ModelContract {\n return this.openai.model({\n ...config,\n // xAI names don't match OpenAI's vision/reasoning prefixes, so we\n // resolve them here and pass explicit flags through — explicit\n // config always wins over the OpenAI adapter's own inference.\n vision: config.vision ?? inferVisionCapability(config.name),\n reasoning: config.reasoning ?? inferReasoningCapability(config.name),\n });\n }\n\n /**\n * Rough token-count estimate. Delegates straight to the wrapped\n * `OpenAISDK.count()` (the shared character-heuristic from the core\n * package — offline, good for budgeting/quota guards, not billing).\n */\n public async count(text: string, model?: string): Promise<number> {\n return this.openai.count(text, model);\n }\n\n /**\n * Build an `EmbedderContract` by delegating to the wrapped\n * `OpenAISDK.embedder()`.\n *\n * NOTE: xAI does not currently expose a public embeddings endpoint, so\n * this is wired for protocol parity but a call to `embed()` /\n * `embedMany()` will fail upstream. Point an embedder at a dedicated\n * embeddings provider (e.g. `@warlock.js/ai-openai`) for vectors.\n */\n public embedder(config: XaiEmbedderConfig): EmbedderContract {\n return this.openai.embedder(config);\n }\n\n /**\n * Build an `ImageModelContract` by delegating to the wrapped\n * `OpenAISDK.image()` for use with `ai.image({ model, prompt })`.\n * Pricing resolution mirrors `model()` (per-model `pricing` > SDK\n * registry > `undefined`).\n */\n public image(config: XaiImageConfig): ImageModelContract {\n return this.openai.image(config);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAa,4BAA4B,CAAC,UAAU,eAAe;;;;;;;;;;;AAYnE,MAAa,+BAA+B,CAAC,UAAU,aAAa;;;;;;;;;;AAWpE,MAAa,kBAAkB;CAC7B;CACA;CACA;CACA;CACA;AACF;;;;;;;;;;;;;AAcA,SAAgB,sBAAsB,SAA0B;CAC9D,MAAM,aAAa,QAAQ,YAAY;CAEvC,OAAO,0BAA0B,MAAM,WAAW,WAAW,WAAW,MAAM,CAAC;AACjF;;;;;;;;;;;;;AAcA,SAAgB,yBAAyB,SAA0B;CACjE,MAAM,aAAa,QAAQ,YAAY;CAEvC,OAAO,6BAA6B,MAAM,WAAW,WAAW,WAAW,MAAM,CAAC;AACpF;;;;;;;;;AC5EA,MAAM,eAAe;;;;;;AAOrB,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CrB,IAAa,SAAb,MAAkD;CAkBhD,AAAO,YAAY,QAAsB;EACvC,MAAM,EAAE,SAAS,UAAU,GAAG,SAAS;EAKvC,KAAK,SAAS,IAAIA,gCAAU;GAC1B,GAAG;GACH,SAAS,WAAW;GACpB,UAAU,YAAY;EACxB,CAAC;EAED,KAAK,UAAU,OAAO;CACxB;;;;;;;;;;;;;;;;;;;CAoBA,AAAO,MAAM,QAAuC;EAClD,OAAO,KAAK,OAAO,MAAM;GACvB,GAAG;GAIH,QAAQ,OAAO,UAAU,sBAAsB,OAAO,IAAI;GAC1D,WAAW,OAAO,aAAa,yBAAyB,OAAO,IAAI;EACrE,CAAC;CACH;;;;;;CAOA,MAAa,MAAM,MAAc,OAAiC;EAChE,OAAO,KAAK,OAAO,MAAM,MAAM,KAAK;CACtC;;;;;;;;;;CAWA,AAAO,SAAS,QAA6C;EAC3D,OAAO,KAAK,OAAO,SAAS,MAAM;CACpC;;;;;;;CAQA,AAAO,MAAM,QAA4C;EACvD,OAAO,KAAK,OAAO,MAAM,MAAM;CACjC;AACF"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["OpenAISDK","isProviderTool","InvalidRequestError"],"sources":["../../../../../../../packages/ai-xai/src/known-models.ts","../../../../../../../packages/ai-xai/src/sdk.ts"],"sourcesContent":["/**\n * Capability inference for xAI Grok model ids.\n *\n * xAI speaks the OpenAI Chat Completions protocol, so the wire-level\n * adapter is `OpenAISDK`. But Grok model names (`grok-4`,\n * `grok-2-vision`, …) don't match OpenAI's `gpt-*` / `o*` prefixes, so\n * OpenAI's own inference lists would mis-classify every Grok model as\n * non-vision / non-reasoning. This module supplies xAI's OWN name lists\n * and the `XaiSDK` wrapper injects the resulting capability flags into\n * each `OpenAIModelConfig` before delegating, so the right capabilities\n * are set even though the names aren't OpenAI names.\n *\n * All lists are matched as a prefix so dated / `-latest` / `-fast`\n * variants (`grok-4-0709`, `grok-2-vision-latest`,\n * `grok-3-mini-beta`) are covered without enumerating every release\n * tag. Devs can always override per-model via\n * `xai.model({ name, vision: true | false, reasoning: true | false })`\n * — explicit config wins over inference in either direction.\n */\n\n/**\n * Model-name prefixes for Grok families that accept image input\n * (vision) on the OpenAI-compatible Chat Completions endpoint.\n *\n * - `grok-4` is natively multimodal (text + image input).\n * - `grok-2-vision` is the dedicated image-understanding Grok 2 model.\n *\n * Text-only families (`grok-3`, `grok-3-mini`, the base `grok-2`\n * text model) are intentionally excluded so passing an image\n * attachment to them surfaces a clear, agent-side capability error\n * rather than an opaque xAI 400.\n */\nexport const XAI_VISION_MODEL_PREFIXES = [\"grok-4\", \"grok-2-vision\"] as const;\n\n/**\n * Model-name prefixes for Grok families that expose internal reasoning\n * and accept reasoning controls (e.g. `reasoning_effort`) on the\n * OpenAI-compatible Chat Completions endpoint.\n *\n * - `grok-4` is a reasoning-first model (it always reasons).\n * - `grok-3-mini` is the \"think\" variant of Grok 3 and reasons; the\n * full-size `grok-3` does not, so it is deliberately NOT covered by\n * the `grok-3-mini` prefix.\n */\nexport const XAI_REASONING_MODEL_PREFIXES = [\"grok-4\", \"grok-3-mini\"] as const;\n\n/**\n * A convenience list of the current public Grok chat model ids, handy\n * for menus, validation, and docs. Not exhaustive of every dated alias\n * xAI publishes — pass any id through `xai.model({ name })`; the prefix\n * inference above handles dated / `-latest` variants.\n *\n * @example\n * XAI_CHAT_MODELS.includes(\"grok-4\"); // → true\n */\nexport const XAI_CHAT_MODELS = [\n \"grok-4\",\n \"grok-3\",\n \"grok-3-mini\",\n \"grok-2-vision\",\n \"grok-2\",\n] as const;\n\n/**\n * Infer whether a given Grok model id supports vision based on xAI's\n * known-prefix list. Unknown ids default to `false` so that passing an\n * image attachment to an unsupported model surfaces a clear,\n * agent-side capability error instead of an opaque xAI 400.\n *\n * @example\n * inferVisionCapability(\"grok-4\"); // → true\n * inferVisionCapability(\"grok-2-vision-latest\"); // → true\n * inferVisionCapability(\"grok-3\"); // → false\n * inferVisionCapability(\"grok-3-mini\"); // → false\n */\nexport function inferVisionCapability(modelId: string): boolean {\n const normalized = modelId.toLowerCase();\n\n return XAI_VISION_MODEL_PREFIXES.some((prefix) => normalized.startsWith(prefix));\n}\n\n/**\n * Infer whether a given Grok model id is a reasoning model based on\n * xAI's known-prefix list. Unknown ids default to `false` so the\n * adapter never forwards an unsupported reasoning param to a\n * non-reasoning model.\n *\n * @example\n * inferReasoningCapability(\"grok-4\"); // → true\n * inferReasoningCapability(\"grok-3-mini\"); // → true\n * inferReasoningCapability(\"grok-3\"); // → false\n * inferReasoningCapability(\"grok-2-vision\"); // → false\n */\nexport function inferReasoningCapability(modelId: string): boolean {\n const normalized = modelId.toLowerCase();\n\n return XAI_REASONING_MODEL_PREFIXES.some((prefix) => normalized.startsWith(prefix));\n}\n","import { InvalidRequestError, isProviderTool, type ModelCallOptions } from \"@warlock.js/ai\";\nimport type {\n EmbedderContract,\n ImageModelContract,\n ModelContract,\n ModelPricing,\n SDKAdapterContract,\n} from \"@warlock.js/ai\";\nimport { OpenAISDK } from \"@warlock.js/ai-openai\";\nimport type {\n XaiEmbedderConfig,\n XaiImageConfig,\n XaiModelConfig,\n XaiSDKConfig,\n} from \"./config.type\";\nimport { inferReasoningCapability, inferVisionCapability } from \"./known-models\";\n\n/**\n * The xAI OpenAI-compatible base URL. xAI exposes Chat Completions at\n * `POST /v1/chat/completions` on this host, so the whole adapter rides\n * on the OpenAI wire protocol.\n */\nconst XAI_BASE_URL = \"https://api.x.ai/v1\";\n\n/**\n * The default `provider` label stamped on every model this SDK\n * produces. Surfaces on `ModelContract.provider`, `AgentReport.model`,\n * logs, and any provider-aware middleware.\n */\nconst XAI_PROVIDER = \"xai\";\n\n/**\n * xAI Grok-backed implementation of `SDKAdapterContract`.\n *\n * **Role.** The package entry point for xAI's Grok models. xAI speaks\n * the OpenAI Chat Completions protocol, so `XaiSDK` is a *thin wrapper*\n * over the already-battle-tested {@link OpenAISDK} from\n * `@warlock.js/ai-openai` — NOT a reimplementation. It constructs one\n * internal `OpenAISDK` pointed at xAI's `baseURL` and labeled\n * `provider: \"xai\"`, then delegates `model()` / `embedder()` /\n * `image()` / `count()` to it. Construct one SDK per account and reuse\n * it everywhere.\n *\n * **Responsibility.**\n * - Owns: the xAI defaults (`baseURL` → `https://api.x.ai/v1`,\n * `provider` → `\"xai\"`) and this provider's OWN capability inference.\n * Grok model names (`grok-4`, `grok-2-vision`, …) don't match\n * OpenAI's `gpt-*` / `o*` prefixes, so before delegating `model()`\n * the wrapper injects the `vision` / `reasoning` flags inferred from\n * xAI's name lists (see `known-models.ts`). Because explicit config\n * wins over OpenAI's inference inside `OpenAIModel`, the produced\n * `ModelContract` carries the correct Grok capabilities.\n * - Does NOT own: the wire protocol, request/response mapping,\n * streaming, tool-call accumulation, error wrapping, or pricing\n * resolution — all of that is the wrapped `OpenAISDK`'s job and is\n * reused verbatim.\n *\n * Modeled as a class (see §4.2 of code-style.md — \"long-lived state\n * across many calls\"): it holds one live `OpenAISDK` (which in turn\n * holds one live `OpenAI` client), fronted by FP usage like the other\n * adapters.\n *\n * @example\n * const xai = new XaiSDK({ apiKey: process.env.XAI_API_KEY! });\n * const model = xai.model({ name: \"grok-4\", temperature: 0.7 });\n * const myAgent = ai.agent({ model });\n *\n * @example\n * // Compose into an `ai.xai` namespace for ergonomic agent wiring.\n * const ai = { agent, tool, systemPrompt, xai: new XaiSDK({ apiKey }) };\n * const fast = ai.agent({ model: ai.xai.model({ name: \"grok-3-mini\" }) });\n */\nexport class XaiSDK implements SDKAdapterContract {\n /**\n * The wrapped OpenAI-compatible adapter doing the actual wire work.\n * Constructed once with xAI's `baseURL` + `provider` and the caller's\n * `apiKey` / client options, then reused for every produced model,\n * embedder, and image model.\n */\n private readonly openai: OpenAISDK;\n\n /**\n * Optional SDK-level pricing registry, kept so `model()` can resolve\n * a per-model entry while still applying this provider's default\n * capability inference. The wrapped `OpenAISDK` also resolves\n * pricing, but we surface it here for parity and to keep the default\n * baseURL/provider injection in one place.\n */\n private readonly pricing?: Record<string, ModelPricing>;\n\n public constructor(config: XaiSDKConfig) {\n const { baseURL, provider, ...rest } = config;\n\n // Inject xAI's defaults — `baseURL` → the xAI OpenAI-compatible\n // endpoint, `provider` → \"xai\" — while still letting the caller\n // override either (e.g. a corporate proxy or a relabeled gateway).\n this.openai = new OpenAISDK({\n ...rest,\n baseURL: baseURL ?? XAI_BASE_URL,\n provider: provider ?? XAI_PROVIDER,\n });\n\n this.pricing = config.pricing;\n }\n\n /**\n * Build a `ModelContract` for a Grok model. Delegates to the wrapped\n * `OpenAISDK.model()` after injecting this provider's OWN capability\n * inference: `vision` and `reasoning` are resolved from xAI's\n * name-prefix lists (see `known-models.ts`) unless the caller set them\n * explicitly. Because explicit config wins over OpenAI's inference\n * inside `OpenAIModel`, the returned model self-identifies as\n * `provider: \"xai\"` and carries Grok's real capabilities even though\n * the model name isn't an OpenAI name.\n *\n * Pricing resolution is left to the wrapped adapter: per-model\n * `config.pricing` wins, otherwise the SDK-level registry entry keyed\n * by `config.name`, otherwise `undefined` (no cost computed).\n *\n * @example\n * xai.model({ name: \"grok-4\" }); // vision + reasoning auto-true\n * xai.model({ name: \"grok-3-mini\" }); // reasoning auto-true, vision false\n */\n public model(config: XaiModelConfig): ModelContract {\n const model = this.openai.model({\n ...config,\n // xAI names don't match OpenAI's vision/reasoning prefixes, so we\n // resolve them here and pass explicit flags through — explicit\n // config always wins over the OpenAI adapter's own inference.\n vision: config.vision ?? inferVisionCapability(config.name),\n reasoning: config.reasoning ?? inferReasoningCapability(config.name),\n });\n // Preserve xAI transport constraints even when a gateway relabels the provider.\n // https://docs.x.ai/developers/tools/web-search — native search uses Responses.\n return {\n name: model.name,\n provider: model.provider,\n capabilities: model.capabilities,\n ...(model.pricing ? { pricing: model.pricing } : {}),\n async complete(messages, options) {\n rejectNativeSearch(model.provider, options);\n return model.complete(messages, options);\n },\n async *stream(messages, options) {\n rejectNativeSearch(model.provider, options);\n yield* model.stream(messages, options);\n },\n ...(model.countTokens ? { countTokens: model.countTokens.bind(model) } : {}),\n };\n }\n\n /**\n * Rough token-count estimate. Delegates straight to the wrapped\n * `OpenAISDK.count()` (the shared character-heuristic from the core\n * package — offline, good for budgeting/quota guards, not billing).\n */\n public async count(text: string, model?: string): Promise<number> {\n return this.openai.count(text, model);\n }\n\n /**\n * Build an `EmbedderContract` by delegating to the wrapped\n * `OpenAISDK.embedder()`.\n *\n * NOTE: xAI does not currently expose a public embeddings endpoint, so\n * this is wired for protocol parity but a call to `embed()` /\n * `embedMany()` will fail upstream. Point an embedder at a dedicated\n * embeddings provider (e.g. `@warlock.js/ai-openai`) for vectors.\n */\n public embedder(config: XaiEmbedderConfig): EmbedderContract {\n return this.openai.embedder(config);\n }\n\n /**\n * Build an `ImageModelContract` by delegating to the wrapped\n * `OpenAISDK.image()` for use with `ai.image({ model, prompt })`.\n * Pricing resolution mirrors `model()` (per-model `pricing` > SDK\n * registry > `undefined`).\n */\n public image(config: XaiImageConfig): ImageModelContract {\n return this.openai.image(config);\n }\n}\n\n/** A provider label does not change the underlying Chat Completions transport. */\nfunction rejectNativeSearch(provider: string, options: ModelCallOptions | undefined): void {\n const entries = [\n ...(options?.providerTools ?? []),\n ...(options?.tools ?? []).filter(isProviderTool),\n ];\n if (\n entries.some(\n (entry) =>\n entry.provider === provider &&\n (entry.definition.type === \"web_search\" || entry.definition.type === \"x_search\"),\n )\n ) {\n throw new InvalidRequestError(\n \"xAI native web_search / x_search requires POST /v1/responses. XaiSDK currently supports Chat Completions only; use xAI's Responses API with the vendor SDK for native search.\",\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAa,4BAA4B,CAAC,UAAU,eAAe;;;;;;;;;;;AAYnE,MAAa,+BAA+B,CAAC,UAAU,aAAa;;;;;;;;;;AAWpE,MAAa,kBAAkB;CAC7B;CACA;CACA;CACA;CACA;AACF;;;;;;;;;;;;;AAcA,SAAgB,sBAAsB,SAA0B;CAC9D,MAAM,aAAa,QAAQ,YAAY;CAEvC,OAAO,0BAA0B,MAAM,WAAW,WAAW,WAAW,MAAM,CAAC;AACjF;;;;;;;;;;;;;AAcA,SAAgB,yBAAyB,SAA0B;CACjE,MAAM,aAAa,QAAQ,YAAY;CAEvC,OAAO,6BAA6B,MAAM,WAAW,WAAW,WAAW,MAAM,CAAC;AACpF;;;;;;;;;AC3EA,MAAM,eAAe;;;;;;AAOrB,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CrB,IAAa,SAAb,MAAkD;CAkBhD,AAAO,YAAY,QAAsB;EACvC,MAAM,EAAE,SAAS,UAAU,GAAG,SAAS;EAKvC,KAAK,SAAS,IAAIA,gCAAU;GAC1B,GAAG;GACH,SAAS,WAAW;GACpB,UAAU,YAAY;EACxB,CAAC;EAED,KAAK,UAAU,OAAO;CACxB;;;;;;;;;;;;;;;;;;;CAoBA,AAAO,MAAM,QAAuC;EAClD,MAAM,QAAQ,KAAK,OAAO,MAAM;GAC9B,GAAG;GAIH,QAAQ,OAAO,UAAU,sBAAsB,OAAO,IAAI;GAC1D,WAAW,OAAO,aAAa,yBAAyB,OAAO,IAAI;EACrE,CAAC;EAGD,OAAO;GACL,MAAM,MAAM;GACZ,UAAU,MAAM;GAChB,cAAc,MAAM;GACpB,GAAI,MAAM,UAAU,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;GAClD,MAAM,SAAS,UAAU,SAAS;IAChC,mBAAmB,MAAM,UAAU,OAAO;IAC1C,OAAO,MAAM,SAAS,UAAU,OAAO;GACzC;GACA,OAAO,OAAO,UAAU,SAAS;IAC/B,mBAAmB,MAAM,UAAU,OAAO;IAC1C,OAAO,MAAM,OAAO,UAAU,OAAO;GACvC;GACA,GAAI,MAAM,cAAc,EAAE,aAAa,MAAM,YAAY,KAAK,KAAK,EAAE,IAAI,CAAC;EAC5E;CACF;;;;;;CAOA,MAAa,MAAM,MAAc,OAAiC;EAChE,OAAO,KAAK,OAAO,MAAM,MAAM,KAAK;CACtC;;;;;;;;;;CAWA,AAAO,SAAS,QAA6C;EAC3D,OAAO,KAAK,OAAO,SAAS,MAAM;CACpC;;;;;;;CAQA,AAAO,MAAM,QAA4C;EACvD,OAAO,KAAK,OAAO,MAAM,MAAM;CACjC;AACF;;AAGA,SAAS,mBAAmB,UAAkB,SAA6C;CAKzF,IACE,CAJA,GAAI,SAAS,iBAAiB,CAAC,GAC/B,IAAI,SAAS,SAAS,CAAC,EAAC,CAAE,OAAOC,6BAAc,CAGzC,CAAC,CAAC,MACL,UACC,MAAM,aAAa,aAClB,MAAM,WAAW,SAAS,gBAAgB,MAAM,WAAW,SAAS,WACzE,GAEA,MAAM,IAAIC,mCACR,+KACF;AAEJ"}
|
package/esm/config.type.d.mts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { OpenAISDKConfig } from "@warlock.js/ai-openai";
|
|
2
1
|
import { EmbedderConfig, ImageModelConfig, ModelConfig } from "@warlock.js/ai";
|
|
3
|
-
|
|
2
|
+
import { OpenAISDKConfig } from "@warlock.js/ai-openai";
|
|
4
3
|
//#region ../../packages/ai-xai/src/config.type.d.ts
|
|
5
4
|
/**
|
|
6
5
|
* Configuration for the xAI Grok SDK adapter.
|
|
@@ -34,7 +33,7 @@ import { EmbedderConfig, ImageModelConfig, ModelConfig } from "@warlock.js/ai";
|
|
|
34
33
|
* pricing: { "grok-4": { input: 3, output: 15 } },
|
|
35
34
|
* });
|
|
36
35
|
*/
|
|
37
|
-
type XaiSDKConfig = OpenAISDKConfig;
|
|
36
|
+
export type XaiSDKConfig = OpenAISDKConfig;
|
|
38
37
|
/**
|
|
39
38
|
* Per-model configuration for `XaiSDK.model()`. `name` is the Grok model
|
|
40
39
|
* id (e.g. `"grok-4"`, `"grok-3"`, `"grok-3-mini"`, `"grok-2-vision"`).
|
|
@@ -51,7 +50,7 @@ type XaiSDKConfig = OpenAISDKConfig;
|
|
|
51
50
|
* xai.model({ name: "grok-2-vision" }); // vision auto-true
|
|
52
51
|
* xai.model({ name: "grok-3", vision: true }); // explicit capability override
|
|
53
52
|
*/
|
|
54
|
-
type XaiModelConfig = ModelConfig & {
|
|
53
|
+
export type XaiModelConfig = ModelConfig & {
|
|
55
54
|
/**
|
|
56
55
|
* Override the auto-inferred vision capability. When omitted, the
|
|
57
56
|
* adapter checks the model id against xAI's known vision families
|
|
@@ -77,6 +76,16 @@ type XaiModelConfig = ModelConfig & {
|
|
|
77
76
|
* `json_schema` — the agent then re-injects a soft schema hint.
|
|
78
77
|
*/
|
|
79
78
|
structuredOutput?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Prompt-cache routing key, sent as `prompt_cache_key` so requests that
|
|
81
|
+
* share a prefix land on the same xAI cache. Use a stable value per
|
|
82
|
+
* conversation or tenant. Sent only while the SDK keeps its default
|
|
83
|
+
* provider label.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* model({ name: "grok-4.3", promptCacheKey: `conversation:${conversationId}` });
|
|
87
|
+
*/
|
|
88
|
+
promptCacheKey?: string;
|
|
80
89
|
};
|
|
81
90
|
/**
|
|
82
91
|
* Per-embedder configuration for `XaiSDK.embedder()`. Mirrors the
|
|
@@ -90,7 +99,7 @@ type XaiModelConfig = ModelConfig & {
|
|
|
90
99
|
* @example
|
|
91
100
|
* xai.embedder({ name: "text-embedding-3-small" }); // delegates; xAI has no embeddings API yet
|
|
92
101
|
*/
|
|
93
|
-
type XaiEmbedderConfig = EmbedderConfig;
|
|
102
|
+
export type XaiEmbedderConfig = EmbedderConfig;
|
|
94
103
|
/**
|
|
95
104
|
* Per-model configuration for `XaiSDK.image()`. Mirrors the neutral
|
|
96
105
|
* {@link ImageModelConfig}.
|
|
@@ -102,7 +111,6 @@ type XaiEmbedderConfig = EmbedderConfig;
|
|
|
102
111
|
* than a verified Grok image model. Use `@warlock.js/ai-openai`'s
|
|
103
112
|
* `image()` for OpenAI-Images-compatible generation.
|
|
104
113
|
*/
|
|
105
|
-
type XaiImageConfig = ImageModelConfig;
|
|
114
|
+
export type XaiImageConfig = ImageModelConfig;
|
|
106
115
|
//#endregion
|
|
107
|
-
export { XaiEmbedderConfig, XaiImageConfig, XaiModelConfig, XaiSDKConfig };
|
|
108
116
|
//# sourceMappingURL=config.type.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.type.d.mts","names":[],"sources":["../../../../../../../packages/ai-xai/src/config.type.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.type.d.mts","names":[],"sources":["../../../../../../../packages/ai-xai/src/config.type.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAmCY,eAAe;;;;;;;;;;;;;;;;;YAkBf,iBAAiB;;;;;;;;EAQ3B;;;;;;;;;EASA;;;;;;;;EAQA;;;;;;;;;;EAUA;;;;;;;;;;;;;;YAeU,oBAAoB;;;;;;;;;;;;YAapB,iBAAiB"}
|
package/esm/known-models.d.mts
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* attachment to them surfaces a clear, agent-side capability error
|
|
31
31
|
* rather than an opaque xAI 400.
|
|
32
32
|
*/
|
|
33
|
-
declare const XAI_VISION_MODEL_PREFIXES: readonly ["grok-4", "grok-2-vision"];
|
|
33
|
+
export declare const XAI_VISION_MODEL_PREFIXES: readonly ["grok-4", "grok-2-vision"];
|
|
34
34
|
/**
|
|
35
35
|
* Model-name prefixes for Grok families that expose internal reasoning
|
|
36
36
|
* and accept reasoning controls (e.g. `reasoning_effort`) on the
|
|
@@ -41,7 +41,7 @@ declare const XAI_VISION_MODEL_PREFIXES: readonly ["grok-4", "grok-2-vision"];
|
|
|
41
41
|
* full-size `grok-3` does not, so it is deliberately NOT covered by
|
|
42
42
|
* the `grok-3-mini` prefix.
|
|
43
43
|
*/
|
|
44
|
-
declare const XAI_REASONING_MODEL_PREFIXES: readonly ["grok-4", "grok-3-mini"];
|
|
44
|
+
export declare const XAI_REASONING_MODEL_PREFIXES: readonly ["grok-4", "grok-3-mini"];
|
|
45
45
|
/**
|
|
46
46
|
* A convenience list of the current public Grok chat model ids, handy
|
|
47
47
|
* for menus, validation, and docs. Not exhaustive of every dated alias
|
|
@@ -51,7 +51,7 @@ declare const XAI_REASONING_MODEL_PREFIXES: readonly ["grok-4", "grok-3-mini"];
|
|
|
51
51
|
* @example
|
|
52
52
|
* XAI_CHAT_MODELS.includes("grok-4"); // → true
|
|
53
53
|
*/
|
|
54
|
-
declare const XAI_CHAT_MODELS: readonly ["grok-4", "grok-3", "grok-3-mini", "grok-2-vision", "grok-2"];
|
|
54
|
+
export declare const XAI_CHAT_MODELS: readonly ["grok-4", "grok-3", "grok-3-mini", "grok-2-vision", "grok-2"];
|
|
55
55
|
/**
|
|
56
56
|
* Infer whether a given Grok model id supports vision based on xAI's
|
|
57
57
|
* known-prefix list. Unknown ids default to `false` so that passing an
|
|
@@ -64,7 +64,7 @@ declare const XAI_CHAT_MODELS: readonly ["grok-4", "grok-3", "grok-3-mini", "gro
|
|
|
64
64
|
* inferVisionCapability("grok-3"); // → false
|
|
65
65
|
* inferVisionCapability("grok-3-mini"); // → false
|
|
66
66
|
*/
|
|
67
|
-
declare function inferVisionCapability(modelId: string): boolean;
|
|
67
|
+
export declare function inferVisionCapability(modelId: string): boolean;
|
|
68
68
|
/**
|
|
69
69
|
* Infer whether a given Grok model id is a reasoning model based on
|
|
70
70
|
* xAI's known-prefix list. Unknown ids default to `false` so the
|
|
@@ -77,7 +77,6 @@ declare function inferVisionCapability(modelId: string): boolean;
|
|
|
77
77
|
* inferReasoningCapability("grok-3"); // → false
|
|
78
78
|
* inferReasoningCapability("grok-2-vision"); // → false
|
|
79
79
|
*/
|
|
80
|
-
declare function inferReasoningCapability(modelId: string): boolean;
|
|
80
|
+
export declare function inferReasoningCapability(modelId: string): boolean;
|
|
81
81
|
//#endregion
|
|
82
|
-
export { XAI_CHAT_MODELS, XAI_REASONING_MODEL_PREFIXES, XAI_VISION_MODEL_PREFIXES, inferReasoningCapability, inferVisionCapability };
|
|
83
82
|
//# sourceMappingURL=known-models.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"known-models.d.mts","names":[],"sources":["../../../../../../../packages/ai-xai/src/known-models.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"known-models.d.mts","names":[],"sources":["../../../../../../../packages/ai-xai/src/known-models.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAgCa;;;;;;;;;;;qBAYA;;;;;;;;;;qBAWA;;;;;;;;;;;;;wBAoBG,sBAAsB;;;;;;;;;;;;;wBAkBtB,yBAAyB"}
|
package/esm/sdk.d.mts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { XaiEmbedderConfig, XaiImageConfig, XaiModelConfig, XaiSDKConfig } from "./config.type.mjs";
|
|
2
2
|
import { EmbedderContract, ImageModelContract, ModelContract, SDKAdapterContract } from "@warlock.js/ai";
|
|
3
|
-
|
|
4
3
|
//#region ../../packages/ai-xai/src/sdk.d.ts
|
|
5
4
|
/**
|
|
6
5
|
* xAI Grok-backed implementation of `SDKAdapterContract`.
|
|
@@ -43,7 +42,7 @@ import { EmbedderContract, ImageModelContract, ModelContract, SDKAdapterContract
|
|
|
43
42
|
* const ai = { agent, tool, systemPrompt, xai: new XaiSDK({ apiKey }) };
|
|
44
43
|
* const fast = ai.agent({ model: ai.xai.model({ name: "grok-3-mini" }) });
|
|
45
44
|
*/
|
|
46
|
-
declare class XaiSDK implements SDKAdapterContract {
|
|
45
|
+
export declare class XaiSDK implements SDKAdapterContract {
|
|
47
46
|
/**
|
|
48
47
|
* The wrapped OpenAI-compatible adapter doing the actual wire work.
|
|
49
48
|
* Constructed once with xAI's `baseURL` + `provider` and the caller's
|
|
@@ -104,5 +103,4 @@ declare class XaiSDK implements SDKAdapterContract {
|
|
|
104
103
|
image(config: XaiImageConfig): ImageModelContract;
|
|
105
104
|
}
|
|
106
105
|
//#endregion
|
|
107
|
-
export { XaiSDK };
|
|
108
106
|
//# sourceMappingURL=sdk.d.mts.map
|
package/esm/sdk.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.d.mts","names":[],"sources":["../../../../../../../packages/ai-xai/src/sdk.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"sdk.d.mts","names":[],"sources":["../../../../../../../packages/ai-xai/src/sdk.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAwEa,kBAAkB;;;;;;;mBAOZ;;;;;;;;mBASA;EAEjB,YAAmB,QAAQ;;;;;;;;;;;;;;;;;;;EAiCpB,MAAM,QAAQ,iBAAiB;;;;;;EAiCzB,MAAM,cAAc,iBAAiB;;;;;;;;;;EAa3C,SAAS,QAAQ,oBAAoB;;;;;;;EAUrC,MAAM,QAAQ,iBAAiB"}
|
package/esm/sdk.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { inferReasoningCapability, inferVisionCapability } from "./known-models.mjs";
|
|
2
|
+
import { InvalidRequestError, isProviderTool } from "@warlock.js/ai";
|
|
2
3
|
import { OpenAISDK } from "@warlock.js/ai-openai";
|
|
3
4
|
|
|
4
5
|
//#region ../../packages/ai-xai/src/sdk.ts
|
|
@@ -84,11 +85,26 @@ var XaiSDK = class {
|
|
|
84
85
|
* xai.model({ name: "grok-3-mini" }); // reasoning auto-true, vision false
|
|
85
86
|
*/
|
|
86
87
|
model(config) {
|
|
87
|
-
|
|
88
|
+
const model = this.openai.model({
|
|
88
89
|
...config,
|
|
89
90
|
vision: config.vision ?? inferVisionCapability(config.name),
|
|
90
91
|
reasoning: config.reasoning ?? inferReasoningCapability(config.name)
|
|
91
92
|
});
|
|
93
|
+
return {
|
|
94
|
+
name: model.name,
|
|
95
|
+
provider: model.provider,
|
|
96
|
+
capabilities: model.capabilities,
|
|
97
|
+
...model.pricing ? { pricing: model.pricing } : {},
|
|
98
|
+
async complete(messages, options) {
|
|
99
|
+
rejectNativeSearch(model.provider, options);
|
|
100
|
+
return model.complete(messages, options);
|
|
101
|
+
},
|
|
102
|
+
async *stream(messages, options) {
|
|
103
|
+
rejectNativeSearch(model.provider, options);
|
|
104
|
+
yield* model.stream(messages, options);
|
|
105
|
+
},
|
|
106
|
+
...model.countTokens ? { countTokens: model.countTokens.bind(model) } : {}
|
|
107
|
+
};
|
|
92
108
|
}
|
|
93
109
|
/**
|
|
94
110
|
* Rough token-count estimate. Delegates straight to the wrapped
|
|
@@ -120,6 +136,10 @@ var XaiSDK = class {
|
|
|
120
136
|
return this.openai.image(config);
|
|
121
137
|
}
|
|
122
138
|
};
|
|
139
|
+
/** A provider label does not change the underlying Chat Completions transport. */
|
|
140
|
+
function rejectNativeSearch(provider, options) {
|
|
141
|
+
if ([...options?.providerTools ?? [], ...(options?.tools ?? []).filter(isProviderTool)].some((entry) => entry.provider === provider && (entry.definition.type === "web_search" || entry.definition.type === "x_search"))) throw new InvalidRequestError("xAI native web_search / x_search requires POST /v1/responses. XaiSDK currently supports Chat Completions only; use xAI's Responses API with the vendor SDK for native search.");
|
|
142
|
+
}
|
|
123
143
|
|
|
124
144
|
//#endregion
|
|
125
145
|
export { XaiSDK };
|
package/esm/sdk.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.mjs","names":[],"sources":["../../../../../../../packages/ai-xai/src/sdk.ts"],"sourcesContent":["import type {\n EmbedderContract,\n ImageModelContract,\n ModelContract,\n ModelPricing,\n SDKAdapterContract,\n} from \"@warlock.js/ai\";\nimport { OpenAISDK } from \"@warlock.js/ai-openai\";\nimport type {\n XaiEmbedderConfig,\n XaiImageConfig,\n XaiModelConfig,\n XaiSDKConfig,\n} from \"./config.type\";\nimport { inferReasoningCapability, inferVisionCapability } from \"./known-models\";\n\n/**\n * The xAI OpenAI-compatible base URL. xAI exposes Chat Completions at\n * `POST /v1/chat/completions` on this host, so the whole adapter rides\n * on the OpenAI wire protocol.\n */\nconst XAI_BASE_URL = \"https://api.x.ai/v1\";\n\n/**\n * The default `provider` label stamped on every model this SDK\n * produces. Surfaces on `ModelContract.provider`, `AgentReport.model`,\n * logs, and any provider-aware middleware.\n */\nconst XAI_PROVIDER = \"xai\";\n\n/**\n * xAI Grok-backed implementation of `SDKAdapterContract`.\n *\n * **Role.** The package entry point for xAI's Grok models. xAI speaks\n * the OpenAI Chat Completions protocol, so `XaiSDK` is a *thin wrapper*\n * over the already-battle-tested {@link OpenAISDK} from\n * `@warlock.js/ai-openai` — NOT a reimplementation. It constructs one\n * internal `OpenAISDK` pointed at xAI's `baseURL` and labeled\n * `provider: \"xai\"`, then delegates `model()` / `embedder()` /\n * `image()` / `count()` to it. Construct one SDK per account and reuse\n * it everywhere.\n *\n * **Responsibility.**\n * - Owns: the xAI defaults (`baseURL` → `https://api.x.ai/v1`,\n * `provider` → `\"xai\"`) and this provider's OWN capability inference.\n * Grok model names (`grok-4`, `grok-2-vision`, …) don't match\n * OpenAI's `gpt-*` / `o*` prefixes, so before delegating `model()`\n * the wrapper injects the `vision` / `reasoning` flags inferred from\n * xAI's name lists (see `known-models.ts`). Because explicit config\n * wins over OpenAI's inference inside `OpenAIModel`, the produced\n * `ModelContract` carries the correct Grok capabilities.\n * - Does NOT own: the wire protocol, request/response mapping,\n * streaming, tool-call accumulation, error wrapping, or pricing\n * resolution — all of that is the wrapped `OpenAISDK`'s job and is\n * reused verbatim.\n *\n * Modeled as a class (see §4.2 of code-style.md — \"long-lived state\n * across many calls\"): it holds one live `OpenAISDK` (which in turn\n * holds one live `OpenAI` client), fronted by FP usage like the other\n * adapters.\n *\n * @example\n * const xai = new XaiSDK({ apiKey: process.env.XAI_API_KEY! });\n * const model = xai.model({ name: \"grok-4\", temperature: 0.7 });\n * const myAgent = ai.agent({ model });\n *\n * @example\n * // Compose into an `ai.xai` namespace for ergonomic agent wiring.\n * const ai = { agent, tool, systemPrompt, xai: new XaiSDK({ apiKey }) };\n * const fast = ai.agent({ model: ai.xai.model({ name: \"grok-3-mini\" }) });\n */\nexport class XaiSDK implements SDKAdapterContract {\n /**\n * The wrapped OpenAI-compatible adapter doing the actual wire work.\n * Constructed once with xAI's `baseURL` + `provider` and the caller's\n * `apiKey` / client options, then reused for every produced model,\n * embedder, and image model.\n */\n private readonly openai: OpenAISDK;\n\n /**\n * Optional SDK-level pricing registry, kept so `model()` can resolve\n * a per-model entry while still applying this provider's default\n * capability inference. The wrapped `OpenAISDK` also resolves\n * pricing, but we surface it here for parity and to keep the default\n * baseURL/provider injection in one place.\n */\n private readonly pricing?: Record<string, ModelPricing>;\n\n public constructor(config: XaiSDKConfig) {\n const { baseURL, provider, ...rest } = config;\n\n // Inject xAI's defaults — `baseURL` → the xAI OpenAI-compatible\n // endpoint, `provider` → \"xai\" — while still letting the caller\n // override either (e.g. a corporate proxy or a relabeled gateway).\n this.openai = new OpenAISDK({\n ...rest,\n baseURL: baseURL ?? XAI_BASE_URL,\n provider: provider ?? XAI_PROVIDER,\n });\n\n this.pricing = config.pricing;\n }\n\n /**\n * Build a `ModelContract` for a Grok model. Delegates to the wrapped\n * `OpenAISDK.model()` after injecting this provider's OWN capability\n * inference: `vision` and `reasoning` are resolved from xAI's\n * name-prefix lists (see `known-models.ts`) unless the caller set them\n * explicitly. Because explicit config wins over OpenAI's inference\n * inside `OpenAIModel`, the returned model self-identifies as\n * `provider: \"xai\"` and carries Grok's real capabilities even though\n * the model name isn't an OpenAI name.\n *\n * Pricing resolution is left to the wrapped adapter: per-model\n * `config.pricing` wins, otherwise the SDK-level registry entry keyed\n * by `config.name`, otherwise `undefined` (no cost computed).\n *\n * @example\n * xai.model({ name: \"grok-4\" }); // vision + reasoning auto-true\n * xai.model({ name: \"grok-3-mini\" }); // reasoning auto-true, vision false\n */\n public model(config: XaiModelConfig): ModelContract {\n
|
|
1
|
+
{"version":3,"file":"sdk.mjs","names":[],"sources":["../../../../../../../packages/ai-xai/src/sdk.ts"],"sourcesContent":["import { InvalidRequestError, isProviderTool, type ModelCallOptions } from \"@warlock.js/ai\";\nimport type {\n EmbedderContract,\n ImageModelContract,\n ModelContract,\n ModelPricing,\n SDKAdapterContract,\n} from \"@warlock.js/ai\";\nimport { OpenAISDK } from \"@warlock.js/ai-openai\";\nimport type {\n XaiEmbedderConfig,\n XaiImageConfig,\n XaiModelConfig,\n XaiSDKConfig,\n} from \"./config.type\";\nimport { inferReasoningCapability, inferVisionCapability } from \"./known-models\";\n\n/**\n * The xAI OpenAI-compatible base URL. xAI exposes Chat Completions at\n * `POST /v1/chat/completions` on this host, so the whole adapter rides\n * on the OpenAI wire protocol.\n */\nconst XAI_BASE_URL = \"https://api.x.ai/v1\";\n\n/**\n * The default `provider` label stamped on every model this SDK\n * produces. Surfaces on `ModelContract.provider`, `AgentReport.model`,\n * logs, and any provider-aware middleware.\n */\nconst XAI_PROVIDER = \"xai\";\n\n/**\n * xAI Grok-backed implementation of `SDKAdapterContract`.\n *\n * **Role.** The package entry point for xAI's Grok models. xAI speaks\n * the OpenAI Chat Completions protocol, so `XaiSDK` is a *thin wrapper*\n * over the already-battle-tested {@link OpenAISDK} from\n * `@warlock.js/ai-openai` — NOT a reimplementation. It constructs one\n * internal `OpenAISDK` pointed at xAI's `baseURL` and labeled\n * `provider: \"xai\"`, then delegates `model()` / `embedder()` /\n * `image()` / `count()` to it. Construct one SDK per account and reuse\n * it everywhere.\n *\n * **Responsibility.**\n * - Owns: the xAI defaults (`baseURL` → `https://api.x.ai/v1`,\n * `provider` → `\"xai\"`) and this provider's OWN capability inference.\n * Grok model names (`grok-4`, `grok-2-vision`, …) don't match\n * OpenAI's `gpt-*` / `o*` prefixes, so before delegating `model()`\n * the wrapper injects the `vision` / `reasoning` flags inferred from\n * xAI's name lists (see `known-models.ts`). Because explicit config\n * wins over OpenAI's inference inside `OpenAIModel`, the produced\n * `ModelContract` carries the correct Grok capabilities.\n * - Does NOT own: the wire protocol, request/response mapping,\n * streaming, tool-call accumulation, error wrapping, or pricing\n * resolution — all of that is the wrapped `OpenAISDK`'s job and is\n * reused verbatim.\n *\n * Modeled as a class (see §4.2 of code-style.md — \"long-lived state\n * across many calls\"): it holds one live `OpenAISDK` (which in turn\n * holds one live `OpenAI` client), fronted by FP usage like the other\n * adapters.\n *\n * @example\n * const xai = new XaiSDK({ apiKey: process.env.XAI_API_KEY! });\n * const model = xai.model({ name: \"grok-4\", temperature: 0.7 });\n * const myAgent = ai.agent({ model });\n *\n * @example\n * // Compose into an `ai.xai` namespace for ergonomic agent wiring.\n * const ai = { agent, tool, systemPrompt, xai: new XaiSDK({ apiKey }) };\n * const fast = ai.agent({ model: ai.xai.model({ name: \"grok-3-mini\" }) });\n */\nexport class XaiSDK implements SDKAdapterContract {\n /**\n * The wrapped OpenAI-compatible adapter doing the actual wire work.\n * Constructed once with xAI's `baseURL` + `provider` and the caller's\n * `apiKey` / client options, then reused for every produced model,\n * embedder, and image model.\n */\n private readonly openai: OpenAISDK;\n\n /**\n * Optional SDK-level pricing registry, kept so `model()` can resolve\n * a per-model entry while still applying this provider's default\n * capability inference. The wrapped `OpenAISDK` also resolves\n * pricing, but we surface it here for parity and to keep the default\n * baseURL/provider injection in one place.\n */\n private readonly pricing?: Record<string, ModelPricing>;\n\n public constructor(config: XaiSDKConfig) {\n const { baseURL, provider, ...rest } = config;\n\n // Inject xAI's defaults — `baseURL` → the xAI OpenAI-compatible\n // endpoint, `provider` → \"xai\" — while still letting the caller\n // override either (e.g. a corporate proxy or a relabeled gateway).\n this.openai = new OpenAISDK({\n ...rest,\n baseURL: baseURL ?? XAI_BASE_URL,\n provider: provider ?? XAI_PROVIDER,\n });\n\n this.pricing = config.pricing;\n }\n\n /**\n * Build a `ModelContract` for a Grok model. Delegates to the wrapped\n * `OpenAISDK.model()` after injecting this provider's OWN capability\n * inference: `vision` and `reasoning` are resolved from xAI's\n * name-prefix lists (see `known-models.ts`) unless the caller set them\n * explicitly. Because explicit config wins over OpenAI's inference\n * inside `OpenAIModel`, the returned model self-identifies as\n * `provider: \"xai\"` and carries Grok's real capabilities even though\n * the model name isn't an OpenAI name.\n *\n * Pricing resolution is left to the wrapped adapter: per-model\n * `config.pricing` wins, otherwise the SDK-level registry entry keyed\n * by `config.name`, otherwise `undefined` (no cost computed).\n *\n * @example\n * xai.model({ name: \"grok-4\" }); // vision + reasoning auto-true\n * xai.model({ name: \"grok-3-mini\" }); // reasoning auto-true, vision false\n */\n public model(config: XaiModelConfig): ModelContract {\n const model = this.openai.model({\n ...config,\n // xAI names don't match OpenAI's vision/reasoning prefixes, so we\n // resolve them here and pass explicit flags through — explicit\n // config always wins over the OpenAI adapter's own inference.\n vision: config.vision ?? inferVisionCapability(config.name),\n reasoning: config.reasoning ?? inferReasoningCapability(config.name),\n });\n // Preserve xAI transport constraints even when a gateway relabels the provider.\n // https://docs.x.ai/developers/tools/web-search — native search uses Responses.\n return {\n name: model.name,\n provider: model.provider,\n capabilities: model.capabilities,\n ...(model.pricing ? { pricing: model.pricing } : {}),\n async complete(messages, options) {\n rejectNativeSearch(model.provider, options);\n return model.complete(messages, options);\n },\n async *stream(messages, options) {\n rejectNativeSearch(model.provider, options);\n yield* model.stream(messages, options);\n },\n ...(model.countTokens ? { countTokens: model.countTokens.bind(model) } : {}),\n };\n }\n\n /**\n * Rough token-count estimate. Delegates straight to the wrapped\n * `OpenAISDK.count()` (the shared character-heuristic from the core\n * package — offline, good for budgeting/quota guards, not billing).\n */\n public async count(text: string, model?: string): Promise<number> {\n return this.openai.count(text, model);\n }\n\n /**\n * Build an `EmbedderContract` by delegating to the wrapped\n * `OpenAISDK.embedder()`.\n *\n * NOTE: xAI does not currently expose a public embeddings endpoint, so\n * this is wired for protocol parity but a call to `embed()` /\n * `embedMany()` will fail upstream. Point an embedder at a dedicated\n * embeddings provider (e.g. `@warlock.js/ai-openai`) for vectors.\n */\n public embedder(config: XaiEmbedderConfig): EmbedderContract {\n return this.openai.embedder(config);\n }\n\n /**\n * Build an `ImageModelContract` by delegating to the wrapped\n * `OpenAISDK.image()` for use with `ai.image({ model, prompt })`.\n * Pricing resolution mirrors `model()` (per-model `pricing` > SDK\n * registry > `undefined`).\n */\n public image(config: XaiImageConfig): ImageModelContract {\n return this.openai.image(config);\n }\n}\n\n/** A provider label does not change the underlying Chat Completions transport. */\nfunction rejectNativeSearch(provider: string, options: ModelCallOptions | undefined): void {\n const entries = [\n ...(options?.providerTools ?? []),\n ...(options?.tools ?? []).filter(isProviderTool),\n ];\n if (\n entries.some(\n (entry) =>\n entry.provider === provider &&\n (entry.definition.type === \"web_search\" || entry.definition.type === \"x_search\"),\n )\n ) {\n throw new InvalidRequestError(\n \"xAI native web_search / x_search requires POST /v1/responses. XaiSDK currently supports Chat Completions only; use xAI's Responses API with the vendor SDK for native search.\",\n );\n }\n}\n"],"mappings":";;;;;;;;;;AAsBA,MAAM,eAAe;;;;;;AAOrB,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CrB,IAAa,SAAb,MAAkD;CAkBhD,AAAO,YAAY,QAAsB;EACvC,MAAM,EAAE,SAAS,UAAU,GAAG,SAAS;EAKvC,KAAK,SAAS,IAAI,UAAU;GAC1B,GAAG;GACH,SAAS,WAAW;GACpB,UAAU,YAAY;EACxB,CAAC;EAED,KAAK,UAAU,OAAO;CACxB;;;;;;;;;;;;;;;;;;;CAoBA,AAAO,MAAM,QAAuC;EAClD,MAAM,QAAQ,KAAK,OAAO,MAAM;GAC9B,GAAG;GAIH,QAAQ,OAAO,UAAU,sBAAsB,OAAO,IAAI;GAC1D,WAAW,OAAO,aAAa,yBAAyB,OAAO,IAAI;EACrE,CAAC;EAGD,OAAO;GACL,MAAM,MAAM;GACZ,UAAU,MAAM;GAChB,cAAc,MAAM;GACpB,GAAI,MAAM,UAAU,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;GAClD,MAAM,SAAS,UAAU,SAAS;IAChC,mBAAmB,MAAM,UAAU,OAAO;IAC1C,OAAO,MAAM,SAAS,UAAU,OAAO;GACzC;GACA,OAAO,OAAO,UAAU,SAAS;IAC/B,mBAAmB,MAAM,UAAU,OAAO;IAC1C,OAAO,MAAM,OAAO,UAAU,OAAO;GACvC;GACA,GAAI,MAAM,cAAc,EAAE,aAAa,MAAM,YAAY,KAAK,KAAK,EAAE,IAAI,CAAC;EAC5E;CACF;;;;;;CAOA,MAAa,MAAM,MAAc,OAAiC;EAChE,OAAO,KAAK,OAAO,MAAM,MAAM,KAAK;CACtC;;;;;;;;;;CAWA,AAAO,SAAS,QAA6C;EAC3D,OAAO,KAAK,OAAO,SAAS,MAAM;CACpC;;;;;;;CAQA,AAAO,MAAM,QAA4C;EACvD,OAAO,KAAK,OAAO,MAAM,MAAM;CACjC;AACF;;AAGA,SAAS,mBAAmB,UAAkB,SAA6C;CAKzF,IACE,CAJA,GAAI,SAAS,iBAAiB,CAAC,GAC/B,IAAI,SAAS,SAAS,CAAC,EAAC,CAAE,OAAO,cAAc,CAGzC,CAAC,CAAC,MACL,UACC,MAAM,aAAa,aAClB,MAAM,WAAW,SAAS,gBAAgB,MAAM,WAAW,SAAS,WACzE,GAEA,MAAM,IAAI,oBACR,+KACF;AAEJ"}
|
package/llms-full.txt
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
name: setup-xai
|
|
11
|
-
description: 'Wire @warlock.js/ai-xai — new XaiSDK({apiKey, baseURL?, provider?, pricing?}) for xAI Grok, .model({name, vision?, reasoning?, structuredOutput?}) for a ModelContract, .embedder({name, dimensions?}) and .image({name, pricing?}) delegated to the OpenAI-compatible adapter. Thin wrapper over OpenAISDK: uses the xAI OpenAI-compatible endpoint (https://api.x.ai/v1) and injects xAI''s own vision/reasoning inference so Grok names resolve to the right capabilities. Triggers: `XaiSDK`, `grok`, `grok-4`, `grok-3`, `grok-3-mini`, `grok-2-vision`, `.model`, `x.ai`, `api.x.ai`, `XAI_API_KEY`, `reasoning_effort` on Grok, "wire xai/grok into a warlock agent", "configure grok-4", "use grok reasoning effort", "send an image to grok-4 / grok-2-vision"; typical import `import { XaiSDK } from "@warlock.js/ai-xai"`. Skip: agent wiring — the `run-ai-agent` topic of the `warlock-js-ai` skill; the underlying OpenAI-compatible adapter and its full capability/streaming/error surface — the `setup-openai` topic of the `warlock-js-ai-openai` skill; adapter comparison — the `pick-ai-provider` topic of the `warlock-js-ai` skill; competing adapters `@warlock.js/ai-anthropic`, `@warlock.js/ai-google`, `@warlock.js/ai-ollama`; raw `openai` SDK pointed at x.ai by hand.'
|
|
11
|
+
description: 'Wire @warlock.js/ai-xai — new XaiSDK({apiKey, baseURL?, provider?, pricing?}) for xAI Grok, .model({name, vision?, reasoning?, structuredOutput?}) for a ModelContract, .embedder({name, dimensions?}) and .image({name, pricing?}) delegated to the OpenAI-compatible adapter. Thin wrapper over OpenAISDK: uses the xAI OpenAI-compatible endpoint (https://api.x.ai/v1) and injects xAI''s own vision/reasoning inference so Grok names resolve to the right capabilities. Triggers: `XaiSDK`, `grok`, `grok-4`, `grok-3`, `grok-3-mini`, `grok-2-vision`, `.model`, `x.ai`, `api.x.ai`, `XAI_API_KEY`, `reasoning_effort` on Grok, `promptCacheKey`, `prompt_cache_key`, xai pricing, "wire xai/grok into a warlock agent", "configure grok-4", "use grok reasoning effort", "send an image to grok-4 / grok-2-vision"; typical import `import { XaiSDK } from "@warlock.js/ai-xai"`. Skip: agent wiring — the `run-ai-agent` topic of the `warlock-js-ai` skill; the underlying OpenAI-compatible adapter and its full capability/streaming/error surface — the `setup-openai` topic of the `warlock-js-ai-openai` skill; adapter comparison — the `pick-ai-provider` topic of the `warlock-js-ai` skill; competing adapters `@warlock.js/ai-anthropic`, `@warlock.js/ai-google`, `@warlock.js/ai-ollama`; raw `openai` SDK pointed at x.ai by hand.'
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# `@warlock.js/ai-xai`
|
|
@@ -32,11 +32,11 @@ const xai = new XaiSDK({ apiKey: process.env.XAI_API_KEY! });
|
|
|
32
32
|
## Producing a model
|
|
33
33
|
|
|
34
34
|
```ts
|
|
35
|
-
xai.model({ name: "grok-4" })
|
|
36
|
-
xai.model({ name: "grok-3-mini" })
|
|
37
|
-
xai.model({ name: "grok-2-vision" })
|
|
38
|
-
xai.model({ name: "grok-4", temperature: 0.2 })
|
|
39
|
-
xai.model({ name: "grok-3", vision: true })
|
|
35
|
+
xai.model({ name: "grok-4" }); // vision + reasoning auto-true
|
|
36
|
+
xai.model({ name: "grok-3-mini" }); // reasoning auto-true, vision false
|
|
37
|
+
xai.model({ name: "grok-2-vision" }); // vision auto-true
|
|
38
|
+
xai.model({ name: "grok-4", temperature: 0.2 }); // sampling controls
|
|
39
|
+
xai.model({ name: "grok-3", vision: true }); // explicit capability override
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
Returns a `ModelContract` you pass straight into `ai.agent({ model })`.
|
|
@@ -45,13 +45,13 @@ Returns a `ModelContract` you pass straight into `ai.agent({ model })`.
|
|
|
45
45
|
|
|
46
46
|
This adapter ships xAI's OWN name lists (Grok ids don't match OpenAI's `gpt-*` / `o*` prefixes). Capabilities are injected per model before delegating; an explicit value always wins over inference.
|
|
47
47
|
|
|
48
|
-
| Model
|
|
49
|
-
|
|
|
50
|
-
| `grok-4`
|
|
51
|
-
| `grok-3`
|
|
52
|
-
| `grok-3-mini`
|
|
53
|
-
| `grok-2-vision` | true
|
|
54
|
-
| `grok-2`
|
|
48
|
+
| Model | `vision` | `reasoning` |
|
|
49
|
+
| --------------- | -------- | -------------------------- |
|
|
50
|
+
| `grok-4` | true | true (reasoning-first) |
|
|
51
|
+
| `grok-3` | false | false |
|
|
52
|
+
| `grok-3-mini` | false | true (the "think" variant) |
|
|
53
|
+
| `grok-2-vision` | true | false |
|
|
54
|
+
| `grok-2` | false | false |
|
|
55
55
|
|
|
56
56
|
- `vision` — inferred `true` for the `grok-4` and `grok-2-vision` prefixes; `false` otherwise.
|
|
57
57
|
- `reasoning` — inferred `true` for `grok-4` and `grok-3-mini`; drives whether `reasoning.effort` is forwarded as `reasoning_effort` on the wire.
|
|
@@ -64,8 +64,8 @@ This adapter ships xAI's OWN name lists (Grok ids don't match OpenAI's `gpt-*` /
|
|
|
64
64
|
## Reasoning (grok-4 / grok-3-mini)
|
|
65
65
|
|
|
66
66
|
```ts
|
|
67
|
-
const model = xai.model({ name: "grok-4" });
|
|
68
|
-
await model.complete(messages, { reasoning: { effort: "high" } });
|
|
67
|
+
const model = xai.model({ name: "grok-4" }); // reasoning auto-true
|
|
68
|
+
await model.complete(messages, { reasoning: { effort: "high" } }); // → reasoning_effort: "high"
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
`reasoning.effort` (`"low" | "medium" | "high"`) maps verbatim to the OpenAI-compatible `reasoning_effort` param. When `capabilities.reasoning` is `false` (e.g. `grok-3`), the option is dropped — the adapter never forwards it. Pin `reasoning: true` to force it for a custom/gateway id.
|
|
@@ -92,26 +92,42 @@ xAI does **not** currently expose a public embeddings endpoint. `embedder()` is
|
|
|
92
92
|
|
|
93
93
|
## Pricing — per-model registry
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
xAI ships **no built-in price table**: every Grok model on https://docs.x.ai/developers/pricing (checked 2026-10-17) bills all tokens at a higher long-context rate once the prompt reaches 200k tokens, which a flat `ModelPricing` cannot express. Pass the rates you use (USD per 1,000,000 tokens; `ModelPricing`: `input`, `output`, optional `cachedInput`). xAI has no cache-write charge. Resolution: per-model `pricing` > SDK registry > `undefined` (no cost computed).
|
|
96
96
|
|
|
97
97
|
```ts
|
|
98
|
+
import { ai, totalCost } from "@warlock.js/ai";
|
|
99
|
+
import { XaiSDK } from "@warlock.js/ai-xai";
|
|
100
|
+
|
|
98
101
|
const xai = new XaiSDK({
|
|
99
|
-
apiKey,
|
|
102
|
+
apiKey: process.env.XAI_API_KEY ?? "",
|
|
100
103
|
pricing: {
|
|
101
|
-
|
|
102
|
-
"grok-3
|
|
104
|
+
// Below-200k rates from xAI's pricing page; long prompts cost more.
|
|
105
|
+
"grok-4.3": { input: 1.25, output: 2.5, cachedInput: 0.2 },
|
|
103
106
|
},
|
|
104
107
|
});
|
|
105
108
|
|
|
106
|
-
const { usage } = await ai.agent({ model: xai.model({ name: "grok-4" }) }).execute("hi");
|
|
107
|
-
usage.cost; //
|
|
109
|
+
const { usage } = await ai.agent({ model: xai.model({ name: "grok-4.3" }) }).execute("hi");
|
|
110
|
+
console.log(totalCost(usage.cost)); // undefined when unpriced
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`usage` follows OpenAI semantics (`prompt_tokens` includes the cached tokens, `inputIncludesCache: true`), and `usage.cost` is attached to every `model.complete()` / streaming `done` once the model is priced.
|
|
114
|
+
|
|
115
|
+
## Prompt caching
|
|
116
|
+
|
|
117
|
+
xAI's Chat Completions accepts `prompt_cache_key`, routed as the `x-grok-conv-id` cache key (https://docs.x.ai/developers/advanced-api-usage/prompt-caching/maximizing-cache-hits). Set `promptCacheKey` on the model — sent while the SDK keeps its default `"xai"` provider label — to keep a conversation's requests on the same cache:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { XaiSDK } from "@warlock.js/ai-xai";
|
|
121
|
+
|
|
122
|
+
const xai = new XaiSDK({ apiKey: process.env.XAI_API_KEY ?? "" });
|
|
123
|
+
const model = xai.model({ name: "grok-4.3", promptCacheKey: "conversation:42" });
|
|
108
124
|
```
|
|
109
125
|
|
|
110
|
-
|
|
126
|
+
OpenAI's `prompt_cache_retention` and explicit breakpoints are never sent to xAI.
|
|
111
127
|
|
|
112
128
|
## Errors
|
|
113
129
|
|
|
114
|
-
Raw xAI / OpenAI-SDK errors are wrapped into the typed `@warlock.js/ai` `AIError` hierarchy by the wrapped adapter's error wrapper (dispatch keys on `APIError.status + code`). See the `handle-ai-errors` topic of the `warlock-js-ai` skill.
|
|
130
|
+
Raw xAI / OpenAI-SDK errors are wrapped into the typed `@warlock.js/ai` `AIError` hierarchy by the wrapped adapter's error wrapper (dispatch keys on `APIError.status + code`). See the `handle-ai-errors` topic of the `warlock-js-ai` skill. HTTP 503 (and OpenAI's `server_is_overloaded` code) maps to `ProviderOverloadedError` (`code: "PROVIDER_OVERLOADED"`, `retryable: true`); every wrapped error carries `status`, `retryable` and `billed` (`false` for 401 / 402 / 403, otherwise `"unknown"`).
|
|
115
131
|
|
|
116
132
|
## When NOT to use this skill
|
|
117
133
|
|
|
@@ -123,6 +139,31 @@ Raw xAI / OpenAI-SDK errors are wrapped into the typed `@warlock.js/ai` `AIError
|
|
|
123
139
|
- The `setup-openai` topic of the `warlock-js-ai-openai` skill — the wrapped adapter; full wire / streaming / structured-output / multipart surface
|
|
124
140
|
- The `run-ai-agent` topic of the `warlock-js-ai` skill — passing the model into `ai.agent({...})`
|
|
125
141
|
- The `pick-ai-provider` topic of the `warlock-js-ai` skill — adapter comparison
|
|
126
|
-
|
|
142
|
+
|
|
143
|
+
## Provider body options and token estimates
|
|
144
|
+
|
|
145
|
+
This adapter delegates Chat Completions to the OpenAI adapter, so
|
|
146
|
+
`providerOptions.openai.body` adds native Chat request fields. Other provider
|
|
147
|
+
keys are ignored. Plain-object fields merge one level deep with neutral options;
|
|
148
|
+
caller-provided keys win, while arrays, scalars and `null` replace the field.
|
|
149
|
+
The OpenAI adapter's protected conversation, tool and transport fields remain
|
|
150
|
+
protected here too. Send only fields supported by this provider; do not reuse
|
|
151
|
+
OpenAI-only bodies across a mixed-provider fallback chain.
|
|
152
|
+
|
|
153
|
+
Models from this adapter have no native `countTokens` method. Check
|
|
154
|
+
`model.countTokens` before using an optional native counting capability;
|
|
155
|
+
`sdk.count(text)` is a separate offline estimate.
|
|
156
|
+
|
|
157
|
+
## Native web search requires Responses
|
|
158
|
+
|
|
159
|
+
[xAI's official web-search guide](https://docs.x.ai/developers/tools/web-search)
|
|
160
|
+
(verified 2026-10-18) sends `{ type: "web_search" }` to `POST /v1/responses`.
|
|
161
|
+
`XaiSDK` currently wraps Chat Completions, so native `web_search` and `x_search`
|
|
162
|
+
provider tools are explicitly unsupported and throw `InvalidRequestError`
|
|
163
|
+
before transport, explaining that the vendor's Responses API is required.
|
|
164
|
+
Use xAI's own Responses SDK for native search. The framework's
|
|
165
|
+
`api: "responses"` adapter remains direct-OpenAI-only; passing a tool definition
|
|
166
|
+
does not change this transport. No xAI hosted-search request count or list fee
|
|
167
|
+
is guessed. See [compatible native search](https://warlock.js.org/v/latest/ai/providers/openai-compatible/#xai).
|
|
127
168
|
|
|
128
169
|
|
package/llms.txt
CHANGED
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
|
|
7
7
|
## Skills
|
|
8
8
|
|
|
9
|
-
- [setup-xai](@warlock.js/ai-xai/setup-xai/SKILL.md): Wire @warlock.js/ai-xai — new XaiSDK({apiKey, baseURL?, provider?, pricing?}) for xAI Grok, .model({name, vision?, reasoning?, structuredOutput?}) for a ModelContract, .embedder({name, dimensions?}) and .image({name, pricing?}) delegated to the OpenAI-compatible adapter. Thin wrapper over OpenAISDK: uses the xAI OpenAI-compatible endpoint (https://api.x.ai/v1) and injects xAI's own vision/reasoning inference so Grok names resolve to the right capabilities. Triggers: `XaiSDK`, `grok`, `grok-4`, `grok-3`, `grok-3-mini`, `grok-2-vision`, `.model`, `x.ai`, `api.x.ai`, `XAI_API_KEY`, `reasoning_effort` on Grok, "wire xai/grok into a warlock agent", "configure grok-4", "use grok reasoning effort", "send an image to grok-4 / grok-2-vision"; typical import `import { XaiSDK } from "@warlock.js/ai-xai"`. Skip: agent wiring — the `run-ai-agent` topic of the `warlock-js-ai` skill; the underlying OpenAI-compatible adapter and its full capability/streaming/error surface — the `setup-openai` topic of the `warlock-js-ai-openai` skill; adapter comparison — the `pick-ai-provider` topic of the `warlock-js-ai` skill; competing adapters `@warlock.js/ai-anthropic`, `@warlock.js/ai-google`, `@warlock.js/ai-ollama`; raw `openai` SDK pointed at x.ai by hand.
|
|
9
|
+
- [setup-xai](@warlock.js/ai-xai/setup-xai/SKILL.md): Wire @warlock.js/ai-xai — new XaiSDK({apiKey, baseURL?, provider?, pricing?}) for xAI Grok, .model({name, vision?, reasoning?, structuredOutput?}) for a ModelContract, .embedder({name, dimensions?}) and .image({name, pricing?}) delegated to the OpenAI-compatible adapter. Thin wrapper over OpenAISDK: uses the xAI OpenAI-compatible endpoint (https://api.x.ai/v1) and injects xAI's own vision/reasoning inference so Grok names resolve to the right capabilities. Triggers: `XaiSDK`, `grok`, `grok-4`, `grok-3`, `grok-3-mini`, `grok-2-vision`, `.model`, `x.ai`, `api.x.ai`, `XAI_API_KEY`, `reasoning_effort` on Grok, `promptCacheKey`, `prompt_cache_key`, xai pricing, "wire xai/grok into a warlock agent", "configure grok-4", "use grok reasoning effort", "send an image to grok-4 / grok-2-vision"; typical import `import { XaiSDK } from "@warlock.js/ai-xai"`. Skip: agent wiring — the `run-ai-agent` topic of the `warlock-js-ai` skill; the underlying OpenAI-compatible adapter and its full capability/streaming/error surface — the `setup-openai` topic of the `warlock-js-ai-openai` skill; adapter comparison — the `pick-ai-provider` topic of the `warlock-js-ai` skill; competing adapters `@warlock.js/ai-anthropic`, `@warlock.js/ai-google`, `@warlock.js/ai-ollama`; raw `openai` SDK pointed at x.ai by hand.
|
package/package.json
CHANGED
|
@@ -15,13 +15,13 @@
|
|
|
15
15
|
"directory": "packages/ai-xai"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@warlock.js/ai-openai": "5.
|
|
19
|
-
"@warlock.js/logger": "5.
|
|
18
|
+
"@warlock.js/ai-openai": "5.32.0",
|
|
19
|
+
"@warlock.js/logger": "5.32.0"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
|
-
"@warlock.js/ai": "5.
|
|
22
|
+
"@warlock.js/ai": "5.32.0"
|
|
23
23
|
},
|
|
24
|
-
"version": "5.
|
|
24
|
+
"version": "5.32.0",
|
|
25
25
|
"main": "./cjs/index.cjs",
|
|
26
26
|
"module": "./esm/index.mjs",
|
|
27
27
|
"types": "./esm/index.d.mts",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: setup-xai
|
|
3
|
-
description: 'Wire @warlock.js/ai-xai — new XaiSDK({apiKey, baseURL?, provider?, pricing?}) for xAI Grok, .model({name, vision?, reasoning?, structuredOutput?}) for a ModelContract, .embedder({name, dimensions?}) and .image({name, pricing?}) delegated to the OpenAI-compatible adapter. Thin wrapper over OpenAISDK: uses the xAI OpenAI-compatible endpoint (https://api.x.ai/v1) and injects xAI''s own vision/reasoning inference so Grok names resolve to the right capabilities. Triggers: `XaiSDK`, `grok`, `grok-4`, `grok-3`, `grok-3-mini`, `grok-2-vision`, `.model`, `x.ai`, `api.x.ai`, `XAI_API_KEY`, `reasoning_effort` on Grok, "wire xai/grok into a warlock agent", "configure grok-4", "use grok reasoning effort", "send an image to grok-4 / grok-2-vision"; typical import `import { XaiSDK } from "@warlock.js/ai-xai"`. Skip: agent wiring — the `run-ai-agent` topic of the `warlock-js-ai` skill; the underlying OpenAI-compatible adapter and its full capability/streaming/error surface — the `setup-openai` topic of the `warlock-js-ai-openai` skill; adapter comparison — the `pick-ai-provider` topic of the `warlock-js-ai` skill; competing adapters `@warlock.js/ai-anthropic`, `@warlock.js/ai-google`, `@warlock.js/ai-ollama`; raw `openai` SDK pointed at x.ai by hand.'
|
|
3
|
+
description: 'Wire @warlock.js/ai-xai — new XaiSDK({apiKey, baseURL?, provider?, pricing?}) for xAI Grok, .model({name, vision?, reasoning?, structuredOutput?}) for a ModelContract, .embedder({name, dimensions?}) and .image({name, pricing?}) delegated to the OpenAI-compatible adapter. Thin wrapper over OpenAISDK: uses the xAI OpenAI-compatible endpoint (https://api.x.ai/v1) and injects xAI''s own vision/reasoning inference so Grok names resolve to the right capabilities. Triggers: `XaiSDK`, `grok`, `grok-4`, `grok-3`, `grok-3-mini`, `grok-2-vision`, `.model`, `x.ai`, `api.x.ai`, `XAI_API_KEY`, `reasoning_effort` on Grok, `promptCacheKey`, `prompt_cache_key`, xai pricing, "wire xai/grok into a warlock agent", "configure grok-4", "use grok reasoning effort", "send an image to grok-4 / grok-2-vision"; typical import `import { XaiSDK } from "@warlock.js/ai-xai"`. Skip: agent wiring — the `run-ai-agent` topic of the `warlock-js-ai` skill; the underlying OpenAI-compatible adapter and its full capability/streaming/error surface — the `setup-openai` topic of the `warlock-js-ai-openai` skill; adapter comparison — the `pick-ai-provider` topic of the `warlock-js-ai` skill; competing adapters `@warlock.js/ai-anthropic`, `@warlock.js/ai-google`, `@warlock.js/ai-ollama`; raw `openai` SDK pointed at x.ai by hand.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# `@warlock.js/ai-xai`
|
|
@@ -24,11 +24,11 @@ const xai = new XaiSDK({ apiKey: process.env.XAI_API_KEY! });
|
|
|
24
24
|
## Producing a model
|
|
25
25
|
|
|
26
26
|
```ts
|
|
27
|
-
xai.model({ name: "grok-4" })
|
|
28
|
-
xai.model({ name: "grok-3-mini" })
|
|
29
|
-
xai.model({ name: "grok-2-vision" })
|
|
30
|
-
xai.model({ name: "grok-4", temperature: 0.2 })
|
|
31
|
-
xai.model({ name: "grok-3", vision: true })
|
|
27
|
+
xai.model({ name: "grok-4" }); // vision + reasoning auto-true
|
|
28
|
+
xai.model({ name: "grok-3-mini" }); // reasoning auto-true, vision false
|
|
29
|
+
xai.model({ name: "grok-2-vision" }); // vision auto-true
|
|
30
|
+
xai.model({ name: "grok-4", temperature: 0.2 }); // sampling controls
|
|
31
|
+
xai.model({ name: "grok-3", vision: true }); // explicit capability override
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
Returns a `ModelContract` you pass straight into `ai.agent({ model })`.
|
|
@@ -37,13 +37,13 @@ Returns a `ModelContract` you pass straight into `ai.agent({ model })`.
|
|
|
37
37
|
|
|
38
38
|
This adapter ships xAI's OWN name lists (Grok ids don't match OpenAI's `gpt-*` / `o*` prefixes). Capabilities are injected per model before delegating; an explicit value always wins over inference.
|
|
39
39
|
|
|
40
|
-
| Model
|
|
41
|
-
|
|
|
42
|
-
| `grok-4`
|
|
43
|
-
| `grok-3`
|
|
44
|
-
| `grok-3-mini`
|
|
45
|
-
| `grok-2-vision` | true
|
|
46
|
-
| `grok-2`
|
|
40
|
+
| Model | `vision` | `reasoning` |
|
|
41
|
+
| --------------- | -------- | -------------------------- |
|
|
42
|
+
| `grok-4` | true | true (reasoning-first) |
|
|
43
|
+
| `grok-3` | false | false |
|
|
44
|
+
| `grok-3-mini` | false | true (the "think" variant) |
|
|
45
|
+
| `grok-2-vision` | true | false |
|
|
46
|
+
| `grok-2` | false | false |
|
|
47
47
|
|
|
48
48
|
- `vision` — inferred `true` for the `grok-4` and `grok-2-vision` prefixes; `false` otherwise.
|
|
49
49
|
- `reasoning` — inferred `true` for `grok-4` and `grok-3-mini`; drives whether `reasoning.effort` is forwarded as `reasoning_effort` on the wire.
|
|
@@ -56,8 +56,8 @@ This adapter ships xAI's OWN name lists (Grok ids don't match OpenAI's `gpt-*` /
|
|
|
56
56
|
## Reasoning (grok-4 / grok-3-mini)
|
|
57
57
|
|
|
58
58
|
```ts
|
|
59
|
-
const model = xai.model({ name: "grok-4" });
|
|
60
|
-
await model.complete(messages, { reasoning: { effort: "high" } });
|
|
59
|
+
const model = xai.model({ name: "grok-4" }); // reasoning auto-true
|
|
60
|
+
await model.complete(messages, { reasoning: { effort: "high" } }); // → reasoning_effort: "high"
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
`reasoning.effort` (`"low" | "medium" | "high"`) maps verbatim to the OpenAI-compatible `reasoning_effort` param. When `capabilities.reasoning` is `false` (e.g. `grok-3`), the option is dropped — the adapter never forwards it. Pin `reasoning: true` to force it for a custom/gateway id.
|
|
@@ -84,26 +84,42 @@ xAI does **not** currently expose a public embeddings endpoint. `embedder()` is
|
|
|
84
84
|
|
|
85
85
|
## Pricing — per-model registry
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
xAI ships **no built-in price table**: every Grok model on https://docs.x.ai/developers/pricing (checked 2026-10-17) bills all tokens at a higher long-context rate once the prompt reaches 200k tokens, which a flat `ModelPricing` cannot express. Pass the rates you use (USD per 1,000,000 tokens; `ModelPricing`: `input`, `output`, optional `cachedInput`). xAI has no cache-write charge. Resolution: per-model `pricing` > SDK registry > `undefined` (no cost computed).
|
|
88
88
|
|
|
89
89
|
```ts
|
|
90
|
+
import { ai, totalCost } from "@warlock.js/ai";
|
|
91
|
+
import { XaiSDK } from "@warlock.js/ai-xai";
|
|
92
|
+
|
|
90
93
|
const xai = new XaiSDK({
|
|
91
|
-
apiKey,
|
|
94
|
+
apiKey: process.env.XAI_API_KEY ?? "",
|
|
92
95
|
pricing: {
|
|
93
|
-
|
|
94
|
-
"grok-3
|
|
96
|
+
// Below-200k rates from xAI's pricing page; long prompts cost more.
|
|
97
|
+
"grok-4.3": { input: 1.25, output: 2.5, cachedInput: 0.2 },
|
|
95
98
|
},
|
|
96
99
|
});
|
|
97
100
|
|
|
98
|
-
const { usage } = await ai.agent({ model: xai.model({ name: "grok-4" }) }).execute("hi");
|
|
99
|
-
usage.cost; //
|
|
101
|
+
const { usage } = await ai.agent({ model: xai.model({ name: "grok-4.3" }) }).execute("hi");
|
|
102
|
+
console.log(totalCost(usage.cost)); // undefined when unpriced
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`usage` follows OpenAI semantics (`prompt_tokens` includes the cached tokens, `inputIncludesCache: true`), and `usage.cost` is attached to every `model.complete()` / streaming `done` once the model is priced.
|
|
106
|
+
|
|
107
|
+
## Prompt caching
|
|
108
|
+
|
|
109
|
+
xAI's Chat Completions accepts `prompt_cache_key`, routed as the `x-grok-conv-id` cache key (https://docs.x.ai/developers/advanced-api-usage/prompt-caching/maximizing-cache-hits). Set `promptCacheKey` on the model — sent while the SDK keeps its default `"xai"` provider label — to keep a conversation's requests on the same cache:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { XaiSDK } from "@warlock.js/ai-xai";
|
|
113
|
+
|
|
114
|
+
const xai = new XaiSDK({ apiKey: process.env.XAI_API_KEY ?? "" });
|
|
115
|
+
const model = xai.model({ name: "grok-4.3", promptCacheKey: "conversation:42" });
|
|
100
116
|
```
|
|
101
117
|
|
|
102
|
-
|
|
118
|
+
OpenAI's `prompt_cache_retention` and explicit breakpoints are never sent to xAI.
|
|
103
119
|
|
|
104
120
|
## Errors
|
|
105
121
|
|
|
106
|
-
Raw xAI / OpenAI-SDK errors are wrapped into the typed `@warlock.js/ai` `AIError` hierarchy by the wrapped adapter's error wrapper (dispatch keys on `APIError.status + code`). See the `handle-ai-errors` topic of the `warlock-js-ai` skill.
|
|
122
|
+
Raw xAI / OpenAI-SDK errors are wrapped into the typed `@warlock.js/ai` `AIError` hierarchy by the wrapped adapter's error wrapper (dispatch keys on `APIError.status + code`). See the `handle-ai-errors` topic of the `warlock-js-ai` skill. HTTP 503 (and OpenAI's `server_is_overloaded` code) maps to `ProviderOverloadedError` (`code: "PROVIDER_OVERLOADED"`, `retryable: true`); every wrapped error carries `status`, `retryable` and `billed` (`false` for 401 / 402 / 403, otherwise `"unknown"`).
|
|
107
123
|
|
|
108
124
|
## When NOT to use this skill
|
|
109
125
|
|
|
@@ -115,4 +131,29 @@ Raw xAI / OpenAI-SDK errors are wrapped into the typed `@warlock.js/ai` `AIError
|
|
|
115
131
|
- The `setup-openai` topic of the `warlock-js-ai-openai` skill — the wrapped adapter; full wire / streaming / structured-output / multipart surface
|
|
116
132
|
- The `run-ai-agent` topic of the `warlock-js-ai` skill — passing the model into `ai.agent({...})`
|
|
117
133
|
- The `pick-ai-provider` topic of the `warlock-js-ai` skill — adapter comparison
|
|
118
|
-
|
|
134
|
+
|
|
135
|
+
## Provider body options and token estimates
|
|
136
|
+
|
|
137
|
+
This adapter delegates Chat Completions to the OpenAI adapter, so
|
|
138
|
+
`providerOptions.openai.body` adds native Chat request fields. Other provider
|
|
139
|
+
keys are ignored. Plain-object fields merge one level deep with neutral options;
|
|
140
|
+
caller-provided keys win, while arrays, scalars and `null` replace the field.
|
|
141
|
+
The OpenAI adapter's protected conversation, tool and transport fields remain
|
|
142
|
+
protected here too. Send only fields supported by this provider; do not reuse
|
|
143
|
+
OpenAI-only bodies across a mixed-provider fallback chain.
|
|
144
|
+
|
|
145
|
+
Models from this adapter have no native `countTokens` method. Check
|
|
146
|
+
`model.countTokens` before using an optional native counting capability;
|
|
147
|
+
`sdk.count(text)` is a separate offline estimate.
|
|
148
|
+
|
|
149
|
+
## Native web search requires Responses
|
|
150
|
+
|
|
151
|
+
[xAI's official web-search guide](https://docs.x.ai/developers/tools/web-search)
|
|
152
|
+
(verified 2026-10-18) sends `{ type: "web_search" }` to `POST /v1/responses`.
|
|
153
|
+
`XaiSDK` currently wraps Chat Completions, so native `web_search` and `x_search`
|
|
154
|
+
provider tools are explicitly unsupported and throw `InvalidRequestError`
|
|
155
|
+
before transport, explaining that the vendor's Responses API is required.
|
|
156
|
+
Use xAI's own Responses SDK for native search. The framework's
|
|
157
|
+
`api: "responses"` adapter remains direct-OpenAI-only; passing a tool definition
|
|
158
|
+
does not change this transport. No xAI hosted-search request count or list fee
|
|
159
|
+
is guessed. See [compatible native search](https://warlock.js.org/v/latest/ai/providers/openai-compatible/#xai).
|