@warlock.js/ai-xai 4.6.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 ADDED
@@ -0,0 +1,15 @@
1
+ # Changelog — @warlock.js/ai-xai
2
+
3
+ All notable changes to `@warlock.js/ai-xai` are documented in this file.
4
+
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
+
7
+ ## 4.6.0
8
+
9
+ ### Added
10
+
11
+ - **First release.** xAI Grok adapter for `@warlock.js/ai` — a thin wrapper over `@warlock.js/ai-openai`'s `OpenAISDK` pinned to `https://api.x.ai/v1` (`provider: "xai"`), so all wire behavior (streaming, tool calls, structured output, error wrapping) is inherited unchanged.
12
+ - **`XaiSDK`** — `.model()` / `.embedder()` / `.image()` / `.count()` delegated to the wrapped client. `baseURL` and `provider` are optional (default to xAI's endpoint / label); every other `openai` `ClientOptions` value is forwarded verbatim.
13
+ - **xAI-specific capability inference** (`inferVisionCapability` / `inferReasoningCapability`, exported alongside `XAI_VISION_MODEL_PREFIXES` / `XAI_REASONING_MODEL_PREFIXES`) — Grok ids don't match OpenAI's `gpt-*` / `o*` prefixes, so `vision` is auto-`true` for `grok-4` / `grok-2-vision` and `reasoning` for `grok-4` / `grok-3-mini`. An explicit `vision` / `reasoning` per model always wins.
14
+ - **`XAI_CHAT_MODELS`** — convenience list of current public Grok chat ids (`grok-4`, `grok-3`, `grok-3-mini`, `grok-2-vision`, `grok-2`).
15
+ - **Optional per-model pricing registry** — resolution at `model()` time is per-model `pricing` > SDK registry > `undefined`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Hassan Zohdy
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,125 @@
1
+ # @warlock.js/ai-xai
2
+
3
+ xAI **Grok** adapter for [`@warlock.js/ai`](../ai). xAI speaks the OpenAI Chat Completions protocol, so this package is a **thin wrapper** over [`@warlock.js/ai-openai`](../ai-openai)'s `OpenAISDK`: it constructs one internal `OpenAISDK` pinned to `https://api.x.ai/v1` with `provider: "xai"` and delegates `model()` / `embedder()` / `image()` / `count()` to it — while injecting xAI's own capability inference so Grok model names resolve to the right `vision` / `reasoning` flags even though they don't match OpenAI's `gpt-*` / `o*` prefixes.
4
+
5
+ ```bash
6
+ npm install @warlock.js/ai @warlock.js/ai-xai @warlock.js/seal openai
7
+ ```
8
+
9
+ > `@warlock.js/seal` is the recommended Standard Schema library for tool inputs and structured output. Any Standard Schema V1 library works (Zod, Valibot, …). `openai` is required because this adapter wraps `@warlock.js/ai-openai`.
10
+
11
+ ## Quick start
12
+
13
+ ```ts
14
+ import { XaiSDK } from "@warlock.js/ai-xai";
15
+ import { ai } from "@warlock.js/ai";
16
+
17
+ const xai = new XaiSDK({ apiKey: process.env.XAI_API_KEY! });
18
+
19
+ const myAgent = ai.agent({
20
+ model: xai.model({ name: "grok-4" }),
21
+ });
22
+
23
+ const result = await myAgent.execute("Hello!");
24
+ console.log(result.text);
25
+ ```
26
+
27
+ `apiKey` is the only required field — `baseURL` defaults to `https://api.x.ai/v1` (the xAI OpenAI-compatible endpoint) and `provider` defaults to `"xai"`. `XaiSDK` is a class holding one long-lived wrapped client; construct one per account and reuse it.
28
+
29
+ ## API surface
30
+
31
+ ```ts
32
+ new XaiSDK(config: XaiSDKConfig) // = OpenAISDKConfig (baseURL/provider default to xAI)
33
+ .model(config: XaiModelConfig) // → ModelContract
34
+ .embedder(config: XaiEmbedderConfig) // → EmbedderContract
35
+ .image(config: XaiImageConfig) // → ImageModelContract
36
+ .count(text, model?) // approximate token count
37
+
38
+ XaiModelConfig {
39
+ name: string; // e.g. "grok-4", "grok-3-mini", "grok-2-vision"
40
+ temperature?: number;
41
+ maxTokens?: number;
42
+ vision?: boolean; // override auto-inference
43
+ reasoning?: boolean; // override auto-inference
44
+ structuredOutput?: boolean; // override; defaults true
45
+ pricing?: ModelPricing; // per-model USD-per-1M rates
46
+ // ...any other ModelConfig field forwarded to the wrapped OpenAI model
47
+ }
48
+ ```
49
+
50
+ ## Models & capabilities
51
+
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
+
54
+ | Model | `vision` | `reasoning` |
55
+ | --------------- | -------- | ----------------------- |
56
+ | `grok-4` | true | true (reasoning-first) |
57
+ | `grok-3` | false | false |
58
+ | `grok-3-mini` | false | true (the "think" variant) |
59
+ | `grok-2-vision` | true | false |
60
+ | `grok-2` | false | false |
61
+
62
+ - `structuredOutput` / `promptCaching` and the image / PDF / audio wire mapping all come from the wrapped OpenAI adapter unchanged.
63
+ - `XAI_CHAT_MODELS`, `XAI_VISION_MODEL_PREFIXES`, and `XAI_REASONING_MODEL_PREFIXES` are exported for menus, validation, and docs.
64
+
65
+ ```ts
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
+ ```
71
+
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.
73
+
74
+ ## Reasoning effort
75
+
76
+ ```ts
77
+ const model = xai.model({ name: "grok-4" }); // reasoning auto-true
78
+ await model.complete(messages, { reasoning: { effort: "high" } }); // → reasoning_effort: "high"
79
+ ```
80
+
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`).
82
+
83
+ ## Pricing
84
+
85
+ `pricing` is an optional registry keyed by model name, rates in **USD per 1,000,000 tokens** (`ModelPricing`). Resolution at `model()` time: per-model `pricing` > SDK registry > `undefined` (no cost computed).
86
+
87
+ ```ts
88
+ const xai = new XaiSDK({
89
+ apiKey,
90
+ pricing: {
91
+ "grok-4": { input: 3, output: 15 },
92
+ "grok-3-mini": { input: 0.3, output: 0.5 },
93
+ },
94
+ });
95
+ ```
96
+
97
+ > Set the current xAI rates yourself — the numbers above are illustrative placeholders.
98
+
99
+ ## Embeddings & images
100
+
101
+ xAI does **not** currently expose a public embeddings endpoint, so `xai.embedder({...})` is wired for protocol parity but a call to `embed()` / `embedMany()` fails upstream — use a dedicated provider (e.g. `@warlock.js/ai-openai`) for vectors. `xai.image({...})` delegates to the wrapped OpenAI Images adapter, which only recognizes the `gpt-image-*` / `dall-e-*` families and rejects any other id at construction; xAI's image generation ("Grok Imagine") is a separate surface.
102
+
103
+ ## OpenAI-compatible endpoints
104
+
105
+ Override `baseURL` (proxy / gateway) or `provider` (relabel the upstream):
106
+
107
+ ```ts
108
+ new XaiSDK({
109
+ apiKey,
110
+ baseURL: "https://gateway.internal/x.ai/v1",
111
+ provider: "xai-proxy",
112
+ });
113
+ ```
114
+
115
+ ## Tests
116
+
117
+ ```bash
118
+ npm test
119
+ ```
120
+
121
+ Covers the wrapped-`OpenAISDK` `baseURL` / `provider` defaults and Grok capability inference.
122
+
123
+ ## License
124
+
125
+ MIT
package/cjs/index.cjs ADDED
@@ -0,0 +1,225 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ let _warlock_js_ai_openai = require("@warlock.js/ai-openai");
3
+
4
+ //#region ../@warlock.js/ai-xai/src/known-models.ts
5
+ /**
6
+ * Capability inference for xAI Grok model ids.
7
+ *
8
+ * xAI speaks the OpenAI Chat Completions protocol, so the wire-level
9
+ * adapter is `OpenAISDK`. But Grok model names (`grok-4`,
10
+ * `grok-2-vision`, …) don't match OpenAI's `gpt-*` / `o*` prefixes, so
11
+ * OpenAI's own inference lists would mis-classify every Grok model as
12
+ * non-vision / non-reasoning. This module supplies xAI's OWN name lists
13
+ * and the `XaiSDK` wrapper injects the resulting capability flags into
14
+ * each `OpenAIModelConfig` before delegating, so the right capabilities
15
+ * are set even though the names aren't OpenAI names.
16
+ *
17
+ * All lists are matched as a prefix so dated / `-latest` / `-fast`
18
+ * variants (`grok-4-0709`, `grok-2-vision-latest`,
19
+ * `grok-3-mini-beta`) are covered without enumerating every release
20
+ * tag. Devs can always override per-model via
21
+ * `xai.model({ name, vision: true | false, reasoning: true | false })`
22
+ * — explicit config wins over inference in either direction.
23
+ */
24
+ /**
25
+ * Model-name prefixes for Grok families that accept image input
26
+ * (vision) on the OpenAI-compatible Chat Completions endpoint.
27
+ *
28
+ * - `grok-4` is natively multimodal (text + image input).
29
+ * - `grok-2-vision` is the dedicated image-understanding Grok 2 model.
30
+ *
31
+ * Text-only families (`grok-3`, `grok-3-mini`, the base `grok-2`
32
+ * text model) are intentionally excluded so passing an image
33
+ * attachment to them surfaces a clear, agent-side capability error
34
+ * rather than an opaque xAI 400.
35
+ */
36
+ const XAI_VISION_MODEL_PREFIXES = ["grok-4", "grok-2-vision"];
37
+ /**
38
+ * Model-name prefixes for Grok families that expose internal reasoning
39
+ * and accept reasoning controls (e.g. `reasoning_effort`) on the
40
+ * OpenAI-compatible Chat Completions endpoint.
41
+ *
42
+ * - `grok-4` is a reasoning-first model (it always reasons).
43
+ * - `grok-3-mini` is the "think" variant of Grok 3 and reasons; the
44
+ * full-size `grok-3` does not, so it is deliberately NOT covered by
45
+ * the `grok-3-mini` prefix.
46
+ */
47
+ const XAI_REASONING_MODEL_PREFIXES = ["grok-4", "grok-3-mini"];
48
+ /**
49
+ * A convenience list of the current public Grok chat model ids, handy
50
+ * for menus, validation, and docs. Not exhaustive of every dated alias
51
+ * xAI publishes — pass any id through `xai.model({ name })`; the prefix
52
+ * inference above handles dated / `-latest` variants.
53
+ *
54
+ * @example
55
+ * XAI_CHAT_MODELS.includes("grok-4"); // → true
56
+ */
57
+ const XAI_CHAT_MODELS = [
58
+ "grok-4",
59
+ "grok-3",
60
+ "grok-3-mini",
61
+ "grok-2-vision",
62
+ "grok-2"
63
+ ];
64
+ /**
65
+ * Infer whether a given Grok model id supports vision based on xAI's
66
+ * known-prefix list. Unknown ids default to `false` so that passing an
67
+ * image attachment to an unsupported model surfaces a clear,
68
+ * agent-side capability error instead of an opaque xAI 400.
69
+ *
70
+ * @example
71
+ * inferVisionCapability("grok-4"); // → true
72
+ * inferVisionCapability("grok-2-vision-latest"); // → true
73
+ * inferVisionCapability("grok-3"); // → false
74
+ * inferVisionCapability("grok-3-mini"); // → false
75
+ */
76
+ function inferVisionCapability(modelId) {
77
+ const normalized = modelId.toLowerCase();
78
+ return XAI_VISION_MODEL_PREFIXES.some((prefix) => normalized.startsWith(prefix));
79
+ }
80
+ /**
81
+ * Infer whether a given Grok model id is a reasoning model based on
82
+ * xAI's known-prefix list. Unknown ids default to `false` so the
83
+ * adapter never forwards an unsupported reasoning param to a
84
+ * non-reasoning model.
85
+ *
86
+ * @example
87
+ * inferReasoningCapability("grok-4"); // → true
88
+ * inferReasoningCapability("grok-3-mini"); // → true
89
+ * inferReasoningCapability("grok-3"); // → false
90
+ * inferReasoningCapability("grok-2-vision"); // → false
91
+ */
92
+ function inferReasoningCapability(modelId) {
93
+ const normalized = modelId.toLowerCase();
94
+ return XAI_REASONING_MODEL_PREFIXES.some((prefix) => normalized.startsWith(prefix));
95
+ }
96
+
97
+ //#endregion
98
+ //#region ../@warlock.js/ai-xai/src/sdk.ts
99
+ /**
100
+ * The xAI OpenAI-compatible base URL. xAI exposes Chat Completions at
101
+ * `POST /v1/chat/completions` on this host, so the whole adapter rides
102
+ * on the OpenAI wire protocol.
103
+ */
104
+ const XAI_BASE_URL = "https://api.x.ai/v1";
105
+ /**
106
+ * The default `provider` label stamped on every model this SDK
107
+ * produces. Surfaces on `ModelContract.provider`, `AgentReport.model`,
108
+ * logs, and any provider-aware middleware.
109
+ */
110
+ const XAI_PROVIDER = "xai";
111
+ /**
112
+ * xAI Grok-backed implementation of `SDKAdapterContract`.
113
+ *
114
+ * **Role.** The package entry point for xAI's Grok models. xAI speaks
115
+ * the OpenAI Chat Completions protocol, so `XaiSDK` is a *thin wrapper*
116
+ * over the already-battle-tested {@link OpenAISDK} from
117
+ * `@warlock.js/ai-openai` — NOT a reimplementation. It constructs one
118
+ * internal `OpenAISDK` pointed at xAI's `baseURL` and labeled
119
+ * `provider: "xai"`, then delegates `model()` / `embedder()` /
120
+ * `image()` / `count()` to it. Construct one SDK per account and reuse
121
+ * it everywhere.
122
+ *
123
+ * **Responsibility.**
124
+ * - Owns: the xAI defaults (`baseURL` → `https://api.x.ai/v1`,
125
+ * `provider` → `"xai"`) and this provider's OWN capability inference.
126
+ * Grok model names (`grok-4`, `grok-2-vision`, …) don't match
127
+ * OpenAI's `gpt-*` / `o*` prefixes, so before delegating `model()`
128
+ * the wrapper injects the `vision` / `reasoning` flags inferred from
129
+ * xAI's name lists (see `known-models.ts`). Because explicit config
130
+ * wins over OpenAI's inference inside `OpenAIModel`, the produced
131
+ * `ModelContract` carries the correct Grok capabilities.
132
+ * - Does NOT own: the wire protocol, request/response mapping,
133
+ * streaming, tool-call accumulation, error wrapping, or pricing
134
+ * resolution — all of that is the wrapped `OpenAISDK`'s job and is
135
+ * reused verbatim.
136
+ *
137
+ * Modeled as a class (see §4.2 of code-style.md — "long-lived state
138
+ * across many calls"): it holds one live `OpenAISDK` (which in turn
139
+ * holds one live `OpenAI` client), fronted by FP usage like the other
140
+ * adapters.
141
+ *
142
+ * @example
143
+ * const xai = new XaiSDK({ apiKey: process.env.XAI_API_KEY! });
144
+ * const model = xai.model({ name: "grok-4", temperature: 0.7 });
145
+ * const myAgent = ai.agent({ model });
146
+ *
147
+ * @example
148
+ * // Compose into an `ai.xai` namespace for ergonomic agent wiring.
149
+ * const ai = { agent, tool, systemPrompt, xai: new XaiSDK({ apiKey }) };
150
+ * const fast = ai.agent({ model: ai.xai.model({ name: "grok-3-mini" }) });
151
+ */
152
+ var XaiSDK = class {
153
+ constructor(config) {
154
+ const { baseURL, provider, ...rest } = config;
155
+ this.openai = new _warlock_js_ai_openai.OpenAISDK({
156
+ ...rest,
157
+ baseURL: baseURL ?? XAI_BASE_URL,
158
+ provider: provider ?? XAI_PROVIDER
159
+ });
160
+ this.pricing = config.pricing;
161
+ }
162
+ /**
163
+ * Build a `ModelContract` for a Grok model. Delegates to the wrapped
164
+ * `OpenAISDK.model()` after injecting this provider's OWN capability
165
+ * inference: `vision` and `reasoning` are resolved from xAI's
166
+ * name-prefix lists (see `known-models.ts`) unless the caller set them
167
+ * explicitly. Because explicit config wins over OpenAI's inference
168
+ * inside `OpenAIModel`, the returned model self-identifies as
169
+ * `provider: "xai"` and carries Grok's real capabilities even though
170
+ * the model name isn't an OpenAI name.
171
+ *
172
+ * Pricing resolution is left to the wrapped adapter: per-model
173
+ * `config.pricing` wins, otherwise the SDK-level registry entry keyed
174
+ * by `config.name`, otherwise `undefined` (no cost computed).
175
+ *
176
+ * @example
177
+ * xai.model({ name: "grok-4" }); // vision + reasoning auto-true
178
+ * xai.model({ name: "grok-3-mini" }); // reasoning auto-true, vision false
179
+ */
180
+ model(config) {
181
+ return this.openai.model({
182
+ ...config,
183
+ vision: config.vision ?? inferVisionCapability(config.name),
184
+ reasoning: config.reasoning ?? inferReasoningCapability(config.name)
185
+ });
186
+ }
187
+ /**
188
+ * Rough token-count estimate. Delegates straight to the wrapped
189
+ * `OpenAISDK.count()` (the shared character-heuristic from the core
190
+ * package — offline, good for budgeting/quota guards, not billing).
191
+ */
192
+ async count(text, model) {
193
+ return this.openai.count(text, model);
194
+ }
195
+ /**
196
+ * Build an `EmbedderContract` by delegating to the wrapped
197
+ * `OpenAISDK.embedder()`.
198
+ *
199
+ * NOTE: xAI does not currently expose a public embeddings endpoint, so
200
+ * this is wired for protocol parity but a call to `embed()` /
201
+ * `embedMany()` will fail upstream. Point an embedder at a dedicated
202
+ * embeddings provider (e.g. `@warlock.js/ai-openai`) for vectors.
203
+ */
204
+ embedder(config) {
205
+ return this.openai.embedder(config);
206
+ }
207
+ /**
208
+ * Build an `ImageModelContract` by delegating to the wrapped
209
+ * `OpenAISDK.image()` for use with `ai.image({ model, prompt })`.
210
+ * Pricing resolution mirrors `model()` (per-model `pricing` > SDK
211
+ * registry > `undefined`).
212
+ */
213
+ image(config) {
214
+ return this.openai.image(config);
215
+ }
216
+ };
217
+
218
+ //#endregion
219
+ exports.XAI_CHAT_MODELS = XAI_CHAT_MODELS;
220
+ exports.XAI_REASONING_MODEL_PREFIXES = XAI_REASONING_MODEL_PREFIXES;
221
+ exports.XAI_VISION_MODEL_PREFIXES = XAI_VISION_MODEL_PREFIXES;
222
+ exports.XaiSDK = XaiSDK;
223
+ exports.inferReasoningCapability = inferReasoningCapability;
224
+ exports.inferVisionCapability = inferVisionCapability;
225
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["OpenAISDK"],"sources":["../../../../../../@warlock.js/ai-xai/src/known-models.ts","../../../../../../@warlock.js/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"}
@@ -0,0 +1,108 @@
1
+ import { OpenAISDKConfig } from "@warlock.js/ai-openai";
2
+ import { EmbedderConfig, ImageModelConfig, ModelConfig } from "@warlock.js/ai";
3
+
4
+ //#region ../@warlock.js/ai-xai/src/config.type.d.ts
5
+ /**
6
+ * Configuration for the xAI Grok SDK adapter.
7
+ *
8
+ * xAI speaks the OpenAI Chat Completions protocol, so `XaiSDK` is a thin
9
+ * wrapper over `OpenAISDK` and this config is the same `OpenAISDKConfig`
10
+ * shape (every upstream `ClientOptions` value — `timeout`, `maxRetries`,
11
+ * `defaultHeaders`, `fetch`, `organization`, … — is forwarded verbatim).
12
+ *
13
+ * The two xAI-specific defaults are applied by the wrapper, so neither
14
+ * is required:
15
+ * - `baseURL` defaults to `https://api.x.ai/v1` (the xAI
16
+ * OpenAI-compatible endpoint). Override only to target a proxy/gateway.
17
+ * - `provider` defaults to `"xai"` — flows through to
18
+ * `ModelContract.provider`, `AgentReport.model.provider`, logs, and any
19
+ * provider-aware middleware. Set it to relabel a gateway upstream.
20
+ *
21
+ * `apiKey` is still required (your xAI API key); everything else is
22
+ * optional. `pricing` is an optional SDK-level registry keyed by model
23
+ * name — resolution at `model()` call time: per-model `pricing` > this
24
+ * SDK registry > `undefined` (no cost computed).
25
+ *
26
+ * @example
27
+ * new XaiSDK({ apiKey: process.env.XAI_API_KEY! });
28
+ *
29
+ * @example
30
+ * // Custom proxy + SDK-level pricing (USD per 1M tokens).
31
+ * new XaiSDK({
32
+ * apiKey,
33
+ * baseURL: "https://gateway.internal/x.ai/v1",
34
+ * pricing: { "grok-4": { input: 3, output: 15 } },
35
+ * });
36
+ */
37
+ type XaiSDKConfig = OpenAISDKConfig;
38
+ /**
39
+ * Per-model configuration for `XaiSDK.model()`. `name` is the Grok model
40
+ * id (e.g. `"grok-4"`, `"grok-3"`, `"grok-3-mini"`, `"grok-2-vision"`).
41
+ *
42
+ * The wrapper injects xAI's OWN capability inference (see
43
+ * `known-models.ts`) before delegating to `OpenAISDK.model()`, so Grok
44
+ * model names resolve to the right `vision` / `reasoning` flags even
45
+ * though they don't match OpenAI's `gpt-*` / `o*` prefixes. Any explicit
46
+ * value below still wins over that inference.
47
+ *
48
+ * @example
49
+ * xai.model({ name: "grok-4" }); // vision + reasoning auto-true
50
+ * xai.model({ name: "grok-3-mini" }); // reasoning auto-true
51
+ * xai.model({ name: "grok-2-vision" }); // vision auto-true
52
+ * xai.model({ name: "grok-3", vision: true }); // explicit capability override
53
+ */
54
+ type XaiModelConfig = ModelConfig & {
55
+ /**
56
+ * Override the auto-inferred vision capability. When omitted, the
57
+ * adapter checks the model id against xAI's known vision families
58
+ * (`grok-4`, `grok-2-vision`; see `known-models.ts`). Explicit
59
+ * `true`/`false` always wins over inference — useful for new Grok
60
+ * variants or a gateway exposing vision under a custom name.
61
+ */
62
+ vision?: boolean;
63
+ /**
64
+ * Override the auto-inferred reasoning capability. When omitted, the
65
+ * adapter checks the model id against xAI's known reasoning families
66
+ * (`grok-4`, `grok-3-mini`; see `known-models.ts`). When capable,
67
+ * `ModelCallOptions.reasoning.effort` is forwarded to the
68
+ * OpenAI-compatible `reasoning_effort` param. Explicit `true`/`false`
69
+ * always wins over inference.
70
+ */
71
+ reasoning?: boolean;
72
+ /**
73
+ * Override the inferred `structuredOutput` capability. xAI supports
74
+ * JSON-schema structured outputs on the Chat Completions endpoint, so
75
+ * the wrapper leaves this to the underlying OpenAI adapter (default
76
+ * `true`). Set `false` for a model/route that rejects strict
77
+ * `json_schema` — the agent then re-injects a soft schema hint.
78
+ */
79
+ structuredOutput?: boolean;
80
+ };
81
+ /**
82
+ * Per-embedder configuration for `XaiSDK.embedder()`. Mirrors the
83
+ * neutral {@link EmbedderConfig}.
84
+ *
85
+ * NOTE: xAI does not currently expose a public embeddings endpoint, so
86
+ * `embedder()` is wired for protocol parity but a call will fail
87
+ * upstream. Use a dedicated embeddings provider (e.g.
88
+ * `@warlock.js/ai-openai`) for vectors.
89
+ *
90
+ * @example
91
+ * xai.embedder({ name: "text-embedding-3-small" }); // delegates; xAI has no embeddings API yet
92
+ */
93
+ type XaiEmbedderConfig = EmbedderConfig;
94
+ /**
95
+ * Per-model configuration for `XaiSDK.image()`. Mirrors the neutral
96
+ * {@link ImageModelConfig}.
97
+ *
98
+ * NOTE: `image()` delegates to the wrapped OpenAI Images adapter, which
99
+ * only recognizes the `gpt-image-*` / `dall-e-*` families and rejects
100
+ * any other id at construction. xAI's image generation ("Grok Imagine")
101
+ * is a separate surface, so this hook exists for protocol parity rather
102
+ * than a verified Grok image model. Use `@warlock.js/ai-openai`'s
103
+ * `image()` for OpenAI-Images-compatible generation.
104
+ */
105
+ type XaiImageConfig = ImageModelConfig;
106
+ //#endregion
107
+ export { XaiEmbedderConfig, XaiImageConfig, XaiModelConfig, XaiSDKConfig };
108
+ //# sourceMappingURL=config.type.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.type.d.mts","names":[],"sources":["../../../../../../@warlock.js/ai-xai/src/config.type.ts"],"mappings":";;;;;;AAwCA;;;;AAA0C;AAkB1C;;;;;;;;;AAyBkB;AAelB;;;;AAA8C;AAa9C;;;;AAA6C;;;;;;KAvEjC,YAAA,GAAe,eAAe;;;;;;;;;;;;;;;;;KAkB9B,cAAA,GAAiB,WAAW;;;;;;;;EAQtC,MAAA;;;;;;;;;EASA,SAAA;;;;;;;;EAQA,gBAAA;AAAA;;;;;;;;;;;;;KAeU,iBAAA,GAAoB,cAAc;;;;;;;;;;;;KAalC,cAAA,GAAiB,gBAAgB"}
@@ -0,0 +1,4 @@
1
+ import { XaiEmbedderConfig, XaiImageConfig, XaiModelConfig, XaiSDKConfig } from "./config.type.mjs";
2
+ import { XaiSDK } from "./sdk.mjs";
3
+ import { XAI_CHAT_MODELS, XAI_REASONING_MODEL_PREFIXES, XAI_VISION_MODEL_PREFIXES, inferReasoningCapability, inferVisionCapability } from "./known-models.mjs";
4
+ export { XAI_CHAT_MODELS, XAI_REASONING_MODEL_PREFIXES, XAI_VISION_MODEL_PREFIXES, type XaiEmbedderConfig, type XaiImageConfig, type XaiModelConfig, XaiSDK, type XaiSDKConfig, inferReasoningCapability, inferVisionCapability };
package/esm/index.mjs ADDED
@@ -0,0 +1,4 @@
1
+ import { XAI_CHAT_MODELS, XAI_REASONING_MODEL_PREFIXES, XAI_VISION_MODEL_PREFIXES, inferReasoningCapability, inferVisionCapability } from "./known-models.mjs";
2
+ import { XaiSDK } from "./sdk.mjs";
3
+
4
+ export { XAI_CHAT_MODELS, XAI_REASONING_MODEL_PREFIXES, XAI_VISION_MODEL_PREFIXES, XaiSDK, inferReasoningCapability, inferVisionCapability };
@@ -0,0 +1,83 @@
1
+ //#region ../@warlock.js/ai-xai/src/known-models.d.ts
2
+ /**
3
+ * Capability inference for xAI Grok model ids.
4
+ *
5
+ * xAI speaks the OpenAI Chat Completions protocol, so the wire-level
6
+ * adapter is `OpenAISDK`. But Grok model names (`grok-4`,
7
+ * `grok-2-vision`, …) don't match OpenAI's `gpt-*` / `o*` prefixes, so
8
+ * OpenAI's own inference lists would mis-classify every Grok model as
9
+ * non-vision / non-reasoning. This module supplies xAI's OWN name lists
10
+ * and the `XaiSDK` wrapper injects the resulting capability flags into
11
+ * each `OpenAIModelConfig` before delegating, so the right capabilities
12
+ * are set even though the names aren't OpenAI names.
13
+ *
14
+ * All lists are matched as a prefix so dated / `-latest` / `-fast`
15
+ * variants (`grok-4-0709`, `grok-2-vision-latest`,
16
+ * `grok-3-mini-beta`) are covered without enumerating every release
17
+ * tag. Devs can always override per-model via
18
+ * `xai.model({ name, vision: true | false, reasoning: true | false })`
19
+ * — explicit config wins over inference in either direction.
20
+ */
21
+ /**
22
+ * Model-name prefixes for Grok families that accept image input
23
+ * (vision) on the OpenAI-compatible Chat Completions endpoint.
24
+ *
25
+ * - `grok-4` is natively multimodal (text + image input).
26
+ * - `grok-2-vision` is the dedicated image-understanding Grok 2 model.
27
+ *
28
+ * Text-only families (`grok-3`, `grok-3-mini`, the base `grok-2`
29
+ * text model) are intentionally excluded so passing an image
30
+ * attachment to them surfaces a clear, agent-side capability error
31
+ * rather than an opaque xAI 400.
32
+ */
33
+ declare const XAI_VISION_MODEL_PREFIXES: readonly ["grok-4", "grok-2-vision"];
34
+ /**
35
+ * Model-name prefixes for Grok families that expose internal reasoning
36
+ * and accept reasoning controls (e.g. `reasoning_effort`) on the
37
+ * OpenAI-compatible Chat Completions endpoint.
38
+ *
39
+ * - `grok-4` is a reasoning-first model (it always reasons).
40
+ * - `grok-3-mini` is the "think" variant of Grok 3 and reasons; the
41
+ * full-size `grok-3` does not, so it is deliberately NOT covered by
42
+ * the `grok-3-mini` prefix.
43
+ */
44
+ declare const XAI_REASONING_MODEL_PREFIXES: readonly ["grok-4", "grok-3-mini"];
45
+ /**
46
+ * A convenience list of the current public Grok chat model ids, handy
47
+ * for menus, validation, and docs. Not exhaustive of every dated alias
48
+ * xAI publishes — pass any id through `xai.model({ name })`; the prefix
49
+ * inference above handles dated / `-latest` variants.
50
+ *
51
+ * @example
52
+ * XAI_CHAT_MODELS.includes("grok-4"); // → true
53
+ */
54
+ declare const XAI_CHAT_MODELS: readonly ["grok-4", "grok-3", "grok-3-mini", "grok-2-vision", "grok-2"];
55
+ /**
56
+ * Infer whether a given Grok model id supports vision based on xAI's
57
+ * known-prefix list. Unknown ids default to `false` so that passing an
58
+ * image attachment to an unsupported model surfaces a clear,
59
+ * agent-side capability error instead of an opaque xAI 400.
60
+ *
61
+ * @example
62
+ * inferVisionCapability("grok-4"); // → true
63
+ * inferVisionCapability("grok-2-vision-latest"); // → true
64
+ * inferVisionCapability("grok-3"); // → false
65
+ * inferVisionCapability("grok-3-mini"); // → false
66
+ */
67
+ declare function inferVisionCapability(modelId: string): boolean;
68
+ /**
69
+ * Infer whether a given Grok model id is a reasoning model based on
70
+ * xAI's known-prefix list. Unknown ids default to `false` so the
71
+ * adapter never forwards an unsupported reasoning param to a
72
+ * non-reasoning model.
73
+ *
74
+ * @example
75
+ * inferReasoningCapability("grok-4"); // → true
76
+ * inferReasoningCapability("grok-3-mini"); // → true
77
+ * inferReasoningCapability("grok-3"); // → false
78
+ * inferReasoningCapability("grok-2-vision"); // → false
79
+ */
80
+ declare function inferReasoningCapability(modelId: string): boolean;
81
+ //#endregion
82
+ export { XAI_CHAT_MODELS, XAI_REASONING_MODEL_PREFIXES, XAI_VISION_MODEL_PREFIXES, inferReasoningCapability, inferVisionCapability };
83
+ //# sourceMappingURL=known-models.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"known-models.d.mts","names":[],"sources":["../../../../../../@warlock.js/ai-xai/src/known-models.ts"],"mappings":";;AAgCA;;;;AAA6E;AAY7E;;;;AAA8E;AAW9E;;;;AAMU;AAcV;;;;AAAqD;AAkBrD;;;;AAAwD;;;;;;cA7D3C,yBAAA;;;;;;;;;;;cAYA,4BAAA;;;;;;;;;;cAWA,eAAA;;;;;;;;;;;;;iBAoBG,qBAAA,CAAsB,OAAe;;;;;;;;;;;;;iBAkBrC,wBAAA,CAAyB,OAAe"}