@tanstack/ai-grok 0.14.9 → 0.14.11
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/dist/esm/adapters/image.js +228 -193
- package/dist/esm/adapters/image.js.map +1 -1
- package/dist/esm/adapters/summarize.js +49 -12
- package/dist/esm/adapters/summarize.js.map +1 -1
- package/dist/esm/adapters/text.js +82 -38
- package/dist/esm/adapters/text.js.map +1 -1
- package/dist/esm/adapters/transcription.js +133 -114
- package/dist/esm/adapters/transcription.js.map +1 -1
- package/dist/esm/adapters/tts.js +147 -130
- package/dist/esm/adapters/tts.js.map +1 -1
- package/dist/esm/adapters/video.js +275 -226
- package/dist/esm/adapters/video.js.map +1 -1
- package/dist/esm/image/image-provider-options.js +64 -66
- package/dist/esm/image/image-provider-options.js.map +1 -1
- package/dist/esm/index.js +3 -31
- package/dist/esm/model-meta.js +149 -47
- package/dist/esm/model-meta.js.map +1 -1
- package/dist/esm/realtime/adapter.js +729 -812
- package/dist/esm/realtime/adapter.js.map +1 -1
- package/dist/esm/realtime/index.js +3 -0
- package/dist/esm/realtime/token.js +78 -72
- package/dist/esm/realtime/token.js.map +1 -1
- package/dist/esm/tools/index.js +57 -96
- package/dist/esm/tools/index.js.map +1 -1
- package/dist/esm/utils/audio.js +116 -162
- package/dist/esm/utils/audio.js.map +1 -1
- package/dist/esm/utils/client.js +22 -16
- package/dist/esm/utils/client.js.map +1 -1
- package/dist/esm/utils/index.js +5 -0
- package/dist/esm/utils/schema-converter.js +2 -0
- package/dist/esm/video/video-provider-options.js +83 -57
- package/dist/esm/video/video-provider-options.js.map +1 -1
- package/package.json +8 -8
- package/src/realtime/adapter.ts +1 -1
- package/src/utils/audio.ts +1 -1
- package/dist/esm/index.js.map +0 -1
|
@@ -1,205 +1,240 @@
|
|
|
1
|
+
import { getGrokApiKeyFromEnv, withGrokDefaults } from "../utils/client.js";
|
|
2
|
+
import { isGrokImagineImageModel, parseGrokImagineSize, validateImageSize, validateNumberOfImages, validatePrompt } from "../image/image-provider-options.js";
|
|
1
3
|
import OpenAI from "openai";
|
|
4
|
+
import { buildImagesUsage } from "@tanstack/openai-base";
|
|
5
|
+
import { generateId } from "@tanstack/ai-utils";
|
|
2
6
|
import { resolveMediaPrompt } from "@tanstack/ai";
|
|
3
7
|
import { BaseImageAdapter } from "@tanstack/ai/adapters";
|
|
4
8
|
import { toRunErrorPayload } from "@tanstack/ai/adapter-internals";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
//#region src/adapters/image.ts
|
|
10
|
+
/** Maximum source images accepted by xAI's image edit endpoint. */
|
|
11
|
+
var MAX_EDIT_IMAGES = 3;
|
|
12
|
+
/**
|
|
13
|
+
* Maps the generic `size` option onto Imagine API parameters: the
|
|
14
|
+
* "aspectRatio_resolution" template ("16:9_2k") splits into `aspect_ratio`
|
|
15
|
+
* and optional `resolution` request fields.
|
|
16
|
+
*/
|
|
10
17
|
function imagineSizeParams(size) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
if (!size) return {};
|
|
19
|
+
const parsed = parseGrokImagineSize(size);
|
|
20
|
+
if (!parsed) return {};
|
|
21
|
+
return {
|
|
22
|
+
aspect_ratio: parsed.aspectRatio,
|
|
23
|
+
...parsed.resolution !== void 0 && { resolution: parsed.resolution }
|
|
24
|
+
};
|
|
18
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Convert a TanStack ImagePart to the URL string accepted by xAI's edit
|
|
28
|
+
* endpoint: public URLs pass through (fetched by xAI's servers), data
|
|
29
|
+
* sources become base64 data URIs.
|
|
30
|
+
*/
|
|
19
31
|
function imagePartToUrl(part) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
class GrokImageAdapter extends BaseImageAdapter {
|
|
24
|
-
kind = "image";
|
|
25
|
-
name = "grok";
|
|
26
|
-
client;
|
|
27
|
-
clientConfig;
|
|
28
|
-
constructor(config, model) {
|
|
29
|
-
super(model, {});
|
|
30
|
-
this.clientConfig = withGrokDefaults(config);
|
|
31
|
-
this.client = new OpenAI(this.clientConfig);
|
|
32
|
-
}
|
|
33
|
-
async generateImages(options) {
|
|
34
|
-
const { model, numberOfImages, size, modelOptions } = options;
|
|
35
|
-
const resolved = resolveMediaPrompt(options.prompt);
|
|
36
|
-
const prompt = resolved.text;
|
|
37
|
-
if (resolved.videos.length > 0 || resolved.audios.length > 0) {
|
|
38
|
-
throw new Error(
|
|
39
|
-
`grok.generateImages does not support video / audio prompt parts on model ${model}.`
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
if (resolved.images.length > 0) {
|
|
43
|
-
if (!isGrokImagineImageModel(model)) {
|
|
44
|
-
throw new Error(
|
|
45
|
-
`grok: model "${model}" does not support image prompt parts. Image-conditioned generation requires an Imagine API model ('grok-imagine-image' or 'grok-imagine-image-quality').`
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
return await this.editImages(options, resolved);
|
|
49
|
-
}
|
|
50
|
-
validatePrompt({ prompt });
|
|
51
|
-
validateImageSize(model, size);
|
|
52
|
-
validateNumberOfImages(model, numberOfImages);
|
|
53
|
-
const isImagine = isGrokImagineImageModel(model);
|
|
54
|
-
const request = {
|
|
55
|
-
model,
|
|
56
|
-
prompt,
|
|
57
|
-
n: numberOfImages ?? 1,
|
|
58
|
-
...isImagine ? imagineSizeParams(size) : size !== void 0 && {
|
|
59
|
-
size
|
|
60
|
-
},
|
|
61
|
-
stream: false,
|
|
62
|
-
...modelOptions
|
|
63
|
-
};
|
|
64
|
-
try {
|
|
65
|
-
options.logger.request(
|
|
66
|
-
`activity=image provider=${this.name} model=${model} n=${request.n ?? 1} size=${request.size ?? "default"}`,
|
|
67
|
-
{ provider: this.name, model }
|
|
68
|
-
);
|
|
69
|
-
const response = await this.client.images.generate(request);
|
|
70
|
-
const images = (response.data ?? []).flatMap(
|
|
71
|
-
(item) => {
|
|
72
|
-
const revisedPrompt = item.revised_prompt;
|
|
73
|
-
if (item.b64_json) {
|
|
74
|
-
return [
|
|
75
|
-
{
|
|
76
|
-
b64Json: item.b64_json,
|
|
77
|
-
...revisedPrompt !== void 0 && { revisedPrompt }
|
|
78
|
-
}
|
|
79
|
-
];
|
|
80
|
-
}
|
|
81
|
-
if (item.url) {
|
|
82
|
-
return [
|
|
83
|
-
{
|
|
84
|
-
url: item.url,
|
|
85
|
-
...revisedPrompt !== void 0 && { revisedPrompt }
|
|
86
|
-
}
|
|
87
|
-
];
|
|
88
|
-
}
|
|
89
|
-
return [];
|
|
90
|
-
}
|
|
91
|
-
);
|
|
92
|
-
const usage = buildImagesUsage(response.usage);
|
|
93
|
-
return {
|
|
94
|
-
id: generateId(this.name),
|
|
95
|
-
model,
|
|
96
|
-
images,
|
|
97
|
-
...usage ? { usage } : {}
|
|
98
|
-
};
|
|
99
|
-
} catch (error) {
|
|
100
|
-
options.logger.errors(`${this.name}.generateImages fatal`, {
|
|
101
|
-
error: toRunErrorPayload(error, `${this.name}.generateImages failed`),
|
|
102
|
-
source: `${this.name}.generateImages`
|
|
103
|
-
});
|
|
104
|
-
throw error;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Image-conditioned generation via xAI's Imagine API.
|
|
109
|
-
*
|
|
110
|
-
* The `/v1/images/edits` endpoint takes `application/json` (the OpenAI
|
|
111
|
-
* SDK's `images.edit()` sends `multipart/form-data`, which xAI rejects),
|
|
112
|
-
* so this path issues the request directly. One input is sent as
|
|
113
|
-
* `image: { url }`; multiple inputs (up to 3) as `images: [{ url }, ...]`,
|
|
114
|
-
* addressed by xAI in the order they are sent. The prompt text is sent
|
|
115
|
-
* verbatim — no referencing markers are injected.
|
|
116
|
-
*/
|
|
117
|
-
async editImages(options, resolved) {
|
|
118
|
-
const { model, numberOfImages, size, modelOptions, logger } = options;
|
|
119
|
-
const prompt = resolved.text;
|
|
120
|
-
const imageInputs = resolved.images;
|
|
121
|
-
const unsupportedRole = imageInputs.find(
|
|
122
|
-
(part) => part.metadata?.role === "mask" || part.metadata?.role === "control"
|
|
123
|
-
);
|
|
124
|
-
if (unsupportedRole) {
|
|
125
|
-
throw new Error(
|
|
126
|
-
`grok: the Imagine API has no ${unsupportedRole.metadata?.role} input; only source/reference images are supported.`
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
if (imageInputs.length > MAX_EDIT_IMAGES) {
|
|
130
|
-
throw new Error(
|
|
131
|
-
`grok: model "${model}" accepts at most ${MAX_EDIT_IMAGES} source images; received ${imageInputs.length}.`
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
validatePrompt({ prompt });
|
|
135
|
-
validateImageSize(model, size);
|
|
136
|
-
validateNumberOfImages(model, numberOfImages);
|
|
137
|
-
const urls = imageInputs.map((part) => imagePartToUrl(part));
|
|
138
|
-
const request = {
|
|
139
|
-
model,
|
|
140
|
-
prompt,
|
|
141
|
-
...urls.length === 1 ? { image: { url: urls[0] } } : { images: urls.map((url) => ({ url })) },
|
|
142
|
-
...numberOfImages !== void 0 && { n: numberOfImages },
|
|
143
|
-
...imagineSizeParams(size),
|
|
144
|
-
...modelOptions
|
|
145
|
-
};
|
|
146
|
-
try {
|
|
147
|
-
logger.request(
|
|
148
|
-
`activity=image provider=${this.name} model=${model} edit images=${urls.length}`,
|
|
149
|
-
{ provider: this.name, model }
|
|
150
|
-
);
|
|
151
|
-
const response = await fetch(
|
|
152
|
-
`${this.clientConfig.baseURL}/images/edits`,
|
|
153
|
-
{
|
|
154
|
-
method: "POST",
|
|
155
|
-
headers: {
|
|
156
|
-
"Content-Type": "application/json",
|
|
157
|
-
Authorization: `Bearer ${this.clientConfig.apiKey}`
|
|
158
|
-
},
|
|
159
|
-
body: JSON.stringify(request)
|
|
160
|
-
}
|
|
161
|
-
);
|
|
162
|
-
if (!response.ok) {
|
|
163
|
-
const body = await response.text();
|
|
164
|
-
throw new Error(
|
|
165
|
-
`grok: image edit request failed (${response.status} ${response.statusText}): ${body}`
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
const result = await response.json();
|
|
169
|
-
const images = (result.data ?? []).flatMap(
|
|
170
|
-
(item) => {
|
|
171
|
-
if (item.b64_json) return [{ b64Json: item.b64_json }];
|
|
172
|
-
if (item.url) return [{ url: item.url }];
|
|
173
|
-
return [];
|
|
174
|
-
}
|
|
175
|
-
);
|
|
176
|
-
if (images.length === 0) {
|
|
177
|
-
throw new Error("grok: image edit response contained no images");
|
|
178
|
-
}
|
|
179
|
-
return {
|
|
180
|
-
id: generateId(this.name),
|
|
181
|
-
model,
|
|
182
|
-
images
|
|
183
|
-
};
|
|
184
|
-
} catch (error) {
|
|
185
|
-
logger.errors(`${this.name}.generateImages fatal`, {
|
|
186
|
-
error: toRunErrorPayload(error, `${this.name}.generateImages failed`),
|
|
187
|
-
source: `${this.name}.generateImages`
|
|
188
|
-
});
|
|
189
|
-
throw error;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
32
|
+
if (part.source.type === "url") return part.source.value;
|
|
33
|
+
return `data:${part.source.mimeType};base64,${part.source.value}`;
|
|
192
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Grok Image Generation Adapter
|
|
37
|
+
*
|
|
38
|
+
* Tree-shakeable adapter for Grok image generation functionality.
|
|
39
|
+
* Supports the legacy grok-2-image-1212 model (text-to-image via the
|
|
40
|
+
* OpenAI-compat endpoint) and the grok-imagine image models, which also
|
|
41
|
+
* accept image prompt parts for image-conditioned generation via xAI's
|
|
42
|
+
* `/v1/images/edits` endpoint (up to 3 source images).
|
|
43
|
+
*
|
|
44
|
+
* Features:
|
|
45
|
+
* - Model-specific type-safe provider options
|
|
46
|
+
* - Size / aspect-ratio validation per model
|
|
47
|
+
* - Number of images validation
|
|
48
|
+
*/
|
|
49
|
+
var GrokImageAdapter = class extends BaseImageAdapter {
|
|
50
|
+
kind = "image";
|
|
51
|
+
name = "grok";
|
|
52
|
+
client;
|
|
53
|
+
clientConfig;
|
|
54
|
+
constructor(config, model) {
|
|
55
|
+
super(model, {});
|
|
56
|
+
this.clientConfig = withGrokDefaults(config);
|
|
57
|
+
this.client = new OpenAI(this.clientConfig);
|
|
58
|
+
}
|
|
59
|
+
async generateImages(options) {
|
|
60
|
+
const { model, numberOfImages, size, modelOptions } = options;
|
|
61
|
+
const resolved = resolveMediaPrompt(options.prompt);
|
|
62
|
+
const prompt = resolved.text;
|
|
63
|
+
if (resolved.videos.length > 0 || resolved.audios.length > 0) throw new Error(`grok.generateImages does not support video / audio prompt parts on model ${model}.`);
|
|
64
|
+
if (resolved.images.length > 0) {
|
|
65
|
+
if (!isGrokImagineImageModel(model)) throw new Error(`grok: model "${model}" does not support image prompt parts. Image-conditioned generation requires an Imagine API model ('grok-imagine-image' or 'grok-imagine-image-quality').`);
|
|
66
|
+
return await this.editImages(options, resolved);
|
|
67
|
+
}
|
|
68
|
+
validatePrompt({
|
|
69
|
+
prompt,
|
|
70
|
+
model
|
|
71
|
+
});
|
|
72
|
+
validateImageSize(model, size);
|
|
73
|
+
validateNumberOfImages(model, numberOfImages);
|
|
74
|
+
const isImagine = isGrokImagineImageModel(model);
|
|
75
|
+
const request = {
|
|
76
|
+
model,
|
|
77
|
+
prompt,
|
|
78
|
+
n: numberOfImages ?? 1,
|
|
79
|
+
...isImagine ? imagineSizeParams(size) : size !== void 0 && { size },
|
|
80
|
+
stream: false,
|
|
81
|
+
...modelOptions
|
|
82
|
+
};
|
|
83
|
+
try {
|
|
84
|
+
options.logger.request(`activity=image provider=${this.name} model=${model} n=${request.n ?? 1} size=${request.size ?? "default"}`, {
|
|
85
|
+
provider: this.name,
|
|
86
|
+
model
|
|
87
|
+
});
|
|
88
|
+
const response = await this.client.images.generate(request);
|
|
89
|
+
const images = (response.data ?? []).flatMap((item) => {
|
|
90
|
+
const revisedPrompt = item.revised_prompt;
|
|
91
|
+
if (item.b64_json) return [{
|
|
92
|
+
b64Json: item.b64_json,
|
|
93
|
+
...revisedPrompt !== void 0 && { revisedPrompt }
|
|
94
|
+
}];
|
|
95
|
+
if (item.url) return [{
|
|
96
|
+
url: item.url,
|
|
97
|
+
...revisedPrompt !== void 0 && { revisedPrompt }
|
|
98
|
+
}];
|
|
99
|
+
return [];
|
|
100
|
+
});
|
|
101
|
+
const usage = buildImagesUsage(response.usage);
|
|
102
|
+
return {
|
|
103
|
+
id: generateId(this.name),
|
|
104
|
+
model,
|
|
105
|
+
images,
|
|
106
|
+
...usage ? { usage } : {}
|
|
107
|
+
};
|
|
108
|
+
} catch (error) {
|
|
109
|
+
options.logger.errors(`${this.name}.generateImages fatal`, {
|
|
110
|
+
error: toRunErrorPayload(error, `${this.name}.generateImages failed`),
|
|
111
|
+
source: `${this.name}.generateImages`
|
|
112
|
+
});
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Image-conditioned generation via xAI's Imagine API.
|
|
118
|
+
*
|
|
119
|
+
* The `/v1/images/edits` endpoint takes `application/json` (the OpenAI
|
|
120
|
+
* SDK's `images.edit()` sends `multipart/form-data`, which xAI rejects),
|
|
121
|
+
* so this path issues the request directly. One input is sent as
|
|
122
|
+
* `image: { url }`; multiple inputs (up to 3) as `images: [{ url }, ...]`,
|
|
123
|
+
* addressed by xAI in the order they are sent. The prompt text is sent
|
|
124
|
+
* verbatim — no referencing markers are injected.
|
|
125
|
+
*/
|
|
126
|
+
async editImages(options, resolved) {
|
|
127
|
+
const { model, numberOfImages, size, modelOptions, logger } = options;
|
|
128
|
+
const prompt = resolved.text;
|
|
129
|
+
const imageInputs = resolved.images;
|
|
130
|
+
const unsupportedRole = imageInputs.find((part) => part.metadata?.role === "mask" || part.metadata?.role === "control");
|
|
131
|
+
if (unsupportedRole) throw new Error(`grok: the Imagine API has no ${unsupportedRole.metadata?.role} input; only source/reference images are supported.`);
|
|
132
|
+
if (imageInputs.length > MAX_EDIT_IMAGES) throw new Error(`grok: model "${model}" accepts at most ${MAX_EDIT_IMAGES} source images; received ${imageInputs.length}.`);
|
|
133
|
+
validatePrompt({
|
|
134
|
+
prompt,
|
|
135
|
+
model
|
|
136
|
+
});
|
|
137
|
+
validateImageSize(model, size);
|
|
138
|
+
validateNumberOfImages(model, numberOfImages);
|
|
139
|
+
const urls = imageInputs.map((part) => imagePartToUrl(part));
|
|
140
|
+
const request = {
|
|
141
|
+
model,
|
|
142
|
+
prompt,
|
|
143
|
+
...urls.length === 1 ? { image: { url: urls[0] } } : { images: urls.map((url) => ({ url })) },
|
|
144
|
+
...numberOfImages !== void 0 && { n: numberOfImages },
|
|
145
|
+
...imagineSizeParams(size),
|
|
146
|
+
...modelOptions
|
|
147
|
+
};
|
|
148
|
+
try {
|
|
149
|
+
logger.request(`activity=image provider=${this.name} model=${model} edit images=${urls.length}`, {
|
|
150
|
+
provider: this.name,
|
|
151
|
+
model
|
|
152
|
+
});
|
|
153
|
+
const response = await fetch(`${this.clientConfig.baseURL}/images/edits`, {
|
|
154
|
+
method: "POST",
|
|
155
|
+
headers: {
|
|
156
|
+
"Content-Type": "application/json",
|
|
157
|
+
Authorization: `Bearer ${this.clientConfig.apiKey}`
|
|
158
|
+
},
|
|
159
|
+
body: JSON.stringify(request)
|
|
160
|
+
});
|
|
161
|
+
if (!response.ok) {
|
|
162
|
+
const body = await response.text();
|
|
163
|
+
throw new Error(`grok: image edit request failed (${response.status} ${response.statusText}): ${body}`);
|
|
164
|
+
}
|
|
165
|
+
const images = ((await response.json()).data ?? []).flatMap((item) => {
|
|
166
|
+
if (item.b64_json) return [{ b64Json: item.b64_json }];
|
|
167
|
+
if (item.url) return [{ url: item.url }];
|
|
168
|
+
return [];
|
|
169
|
+
});
|
|
170
|
+
if (images.length === 0) throw new Error("grok: image edit response contained no images");
|
|
171
|
+
return {
|
|
172
|
+
id: generateId(this.name),
|
|
173
|
+
model,
|
|
174
|
+
images
|
|
175
|
+
};
|
|
176
|
+
} catch (error) {
|
|
177
|
+
logger.errors(`${this.name}.generateImages fatal`, {
|
|
178
|
+
error: toRunErrorPayload(error, `${this.name}.generateImages failed`),
|
|
179
|
+
source: `${this.name}.generateImages`
|
|
180
|
+
});
|
|
181
|
+
throw error;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* Creates a Grok image adapter with explicit API key.
|
|
187
|
+
* Type resolution happens here at the call site.
|
|
188
|
+
*
|
|
189
|
+
* @param model - The model name (e.g., 'grok-2-image-1212')
|
|
190
|
+
* @param apiKey - Your xAI API key
|
|
191
|
+
* @param config - Optional additional configuration
|
|
192
|
+
* @returns Configured Grok image adapter instance with resolved types
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* const adapter = createGrokImage('grok-2-image-1212', "xai-...");
|
|
197
|
+
*
|
|
198
|
+
* const result = await generateImage({
|
|
199
|
+
* adapter,
|
|
200
|
+
* prompt: 'A cute baby sea otter'
|
|
201
|
+
* });
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
193
204
|
function createGrokImage(model, apiKey, config) {
|
|
194
|
-
|
|
205
|
+
return new GrokImageAdapter({
|
|
206
|
+
apiKey,
|
|
207
|
+
...config
|
|
208
|
+
}, model);
|
|
195
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* Creates a Grok image adapter with automatic API key detection from environment variables.
|
|
212
|
+
* Type resolution happens here at the call site.
|
|
213
|
+
*
|
|
214
|
+
* Looks for `XAI_API_KEY` in:
|
|
215
|
+
* - `process.env` (Node.js)
|
|
216
|
+
* - `window.env` (Browser with injected env)
|
|
217
|
+
*
|
|
218
|
+
* @param model - The model name (e.g., 'grok-2-image-1212')
|
|
219
|
+
* @param config - Optional configuration (excluding apiKey which is auto-detected)
|
|
220
|
+
* @returns Configured Grok image adapter instance with resolved types
|
|
221
|
+
* @throws Error if XAI_API_KEY is not found in environment
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```typescript
|
|
225
|
+
* // Automatically uses XAI_API_KEY from environment
|
|
226
|
+
* const adapter = grokImage('grok-2-image-1212');
|
|
227
|
+
*
|
|
228
|
+
* const result = await generateImage({
|
|
229
|
+
* adapter,
|
|
230
|
+
* prompt: 'A beautiful sunset over mountains'
|
|
231
|
+
* });
|
|
232
|
+
* ```
|
|
233
|
+
*/
|
|
196
234
|
function grokImage(model, config) {
|
|
197
|
-
|
|
198
|
-
return createGrokImage(model, apiKey, config);
|
|
235
|
+
return createGrokImage(model, getGrokApiKeyFromEnv(), config);
|
|
199
236
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
};
|
|
205
|
-
//# sourceMappingURL=image.js.map
|
|
237
|
+
//#endregion
|
|
238
|
+
export { GrokImageAdapter, createGrokImage, grokImage };
|
|
239
|
+
|
|
240
|
+
//# sourceMappingURL=image.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.js","sources":["../../../src/adapters/image.ts"],"sourcesContent":["import OpenAI from 'openai'\nimport { resolveMediaPrompt } from '@tanstack/ai'\nimport { BaseImageAdapter } from '@tanstack/ai/adapters'\nimport { toRunErrorPayload } from '@tanstack/ai/adapter-internals'\nimport { buildImagesUsage } from '@tanstack/openai-base'\nimport { generateId } from '@tanstack/ai-utils'\nimport { getGrokApiKeyFromEnv, withGrokDefaults } from '../utils/client'\nimport {\n isGrokImagineImageModel,\n parseGrokImagineSize,\n validateImageSize,\n validateNumberOfImages,\n validatePrompt,\n} from '../image/image-provider-options'\nimport type {\n GeneratedImage,\n ImageGenerationOptions,\n ImageGenerationResult,\n ImagePart,\n MediaInputMetadata,\n ResolvedMediaPrompt,\n} from '@tanstack/ai'\nimport type OpenAI_SDK from 'openai'\nimport type { GrokImageModel } from '../model-meta'\nimport type {\n GrokImageModelInputModalitiesByName,\n GrokImageModelProviderOptionsByName,\n GrokImageModelSizeByName,\n GrokImageProviderOptions,\n} from '../image/image-provider-options'\nimport type { GrokClientConfig } from '../utils/client'\n\n/**\n * Configuration for Grok image adapter\n */\nexport interface GrokImageConfig extends GrokClientConfig {}\n\n/** Maximum source images accepted by xAI's image edit endpoint. */\nconst MAX_EDIT_IMAGES = 3\n\n/**\n * Maps the generic `size` option onto Imagine API parameters: the\n * \"aspectRatio_resolution\" template (\"16:9_2k\") splits into `aspect_ratio`\n * and optional `resolution` request fields.\n */\nfunction imagineSizeParams(size: string | undefined): {\n aspect_ratio?: string\n resolution?: string\n} {\n if (!size) return {}\n const parsed = parseGrokImagineSize(size)\n if (!parsed) return {}\n return {\n aspect_ratio: parsed.aspectRatio,\n ...(parsed.resolution !== undefined && { resolution: parsed.resolution }),\n }\n}\n\n/**\n * Convert a TanStack ImagePart to the URL string accepted by xAI's edit\n * endpoint: public URLs pass through (fetched by xAI's servers), data\n * sources become base64 data URIs.\n */\nfunction imagePartToUrl(part: ImagePart<MediaInputMetadata>): string {\n if (part.source.type === 'url') return part.source.value\n return `data:${part.source.mimeType};base64,${part.source.value}`\n}\n\n/** Response shape of xAI's `/v1/images/edits` endpoint. */\ninterface GrokImageEditResponse {\n data?: Array<{\n url?: string | null\n b64_json?: string | null\n mime_type?: string\n }>\n}\n\n/**\n * Grok Image Generation Adapter\n *\n * Tree-shakeable adapter for Grok image generation functionality.\n * Supports the legacy grok-2-image-1212 model (text-to-image via the\n * OpenAI-compat endpoint) and the grok-imagine image models, which also\n * accept image prompt parts for image-conditioned generation via xAI's\n * `/v1/images/edits` endpoint (up to 3 source images).\n *\n * Features:\n * - Model-specific type-safe provider options\n * - Size / aspect-ratio validation per model\n * - Number of images validation\n */\nexport class GrokImageAdapter<\n TModel extends GrokImageModel,\n> extends BaseImageAdapter<\n TModel,\n GrokImageProviderOptions,\n GrokImageModelProviderOptionsByName,\n GrokImageModelSizeByName,\n GrokImageModelInputModalitiesByName\n> {\n override readonly kind = 'image' as const\n readonly name = 'grok' as const\n\n protected client: OpenAI\n private readonly clientConfig: GrokImageConfig\n\n constructor(config: GrokImageConfig, model: TModel) {\n super(model, {})\n this.clientConfig = withGrokDefaults(config)\n this.client = new OpenAI(this.clientConfig)\n }\n\n async generateImages(\n options: ImageGenerationOptions<GrokImageProviderOptions>,\n ): Promise<ImageGenerationResult> {\n const { model, numberOfImages, size, modelOptions } = options\n\n const resolved = resolveMediaPrompt(options.prompt)\n const prompt = resolved.text\n\n if (resolved.videos.length > 0 || resolved.audios.length > 0) {\n throw new Error(\n `grok.generateImages does not support video / audio prompt parts on model ${model}.`,\n )\n }\n\n if (resolved.images.length > 0) {\n if (!isGrokImagineImageModel(model)) {\n throw new Error(\n `grok: model \"${model}\" does not support image prompt parts. ` +\n `Image-conditioned generation requires an Imagine API model ` +\n `('grok-imagine-image' or 'grok-imagine-image-quality').`,\n )\n }\n return await this.editImages(options, resolved)\n }\n\n validatePrompt({ prompt, model })\n validateImageSize(model, size)\n validateNumberOfImages(model, numberOfImages)\n\n // grok-imagine models are aspect-ratio sized: the generic `size` option\n // carries an \"aspectRatio_resolution\" template (e.g. '16:9_2k', like\n // Gemini native image models) and maps to the Imagine API's\n // `aspect_ratio` / `resolution` parameters instead of OpenAI-style `size`.\n const isImagine = isGrokImagineImageModel(model)\n const request = {\n model,\n prompt,\n n: numberOfImages ?? 1,\n ...(isImagine\n ? imagineSizeParams(size)\n : size !== undefined && {\n size: size,\n }),\n stream: false,\n ...modelOptions,\n } as OpenAI_SDK.Images.ImageGenerateParamsNonStreaming\n\n try {\n options.logger.request(\n `activity=image provider=${this.name} model=${model} n=${request.n ?? 1} size=${request.size ?? 'default'}`,\n { provider: this.name, model },\n )\n const response = await this.client.images.generate(request)\n\n const images: Array<GeneratedImage> = (response.data ?? []).flatMap(\n (item): Array<GeneratedImage> => {\n const revisedPrompt = item.revised_prompt\n if (item.b64_json) {\n return [\n {\n b64Json: item.b64_json,\n ...(revisedPrompt !== undefined && { revisedPrompt }),\n },\n ]\n }\n if (item.url) {\n return [\n {\n url: item.url,\n ...(revisedPrompt !== undefined && { revisedPrompt }),\n },\n ]\n }\n return []\n },\n )\n\n const usage = buildImagesUsage(response.usage)\n\n return {\n id: generateId(this.name),\n model,\n images,\n ...(usage ? { usage } : {}),\n }\n } catch (error: unknown) {\n options.logger.errors(`${this.name}.generateImages fatal`, {\n error: toRunErrorPayload(error, `${this.name}.generateImages failed`),\n source: `${this.name}.generateImages`,\n })\n throw error\n }\n }\n\n /**\n * Image-conditioned generation via xAI's Imagine API.\n *\n * The `/v1/images/edits` endpoint takes `application/json` (the OpenAI\n * SDK's `images.edit()` sends `multipart/form-data`, which xAI rejects),\n * so this path issues the request directly. One input is sent as\n * `image: { url }`; multiple inputs (up to 3) as `images: [{ url }, ...]`,\n * addressed by xAI in the order they are sent. The prompt text is sent\n * verbatim — no referencing markers are injected.\n */\n private async editImages(\n options: ImageGenerationOptions<GrokImageProviderOptions>,\n resolved: ResolvedMediaPrompt,\n ): Promise<ImageGenerationResult> {\n const { model, numberOfImages, size, modelOptions, logger } = options\n const prompt = resolved.text\n const imageInputs = resolved.images\n\n const unsupportedRole = imageInputs.find(\n (part) =>\n part.metadata?.role === 'mask' || part.metadata?.role === 'control',\n )\n if (unsupportedRole) {\n throw new Error(\n `grok: the Imagine API has no ${unsupportedRole.metadata?.role} input; ` +\n `only source/reference images are supported.`,\n )\n }\n if (imageInputs.length > MAX_EDIT_IMAGES) {\n throw new Error(\n `grok: model \"${model}\" accepts at most ${MAX_EDIT_IMAGES} source images; received ${imageInputs.length}.`,\n )\n }\n\n validatePrompt({ prompt, model })\n validateImageSize(model, size)\n validateNumberOfImages(model, numberOfImages)\n\n const urls = imageInputs.map((part) => imagePartToUrl(part))\n const request: Record<string, unknown> = {\n model,\n prompt,\n ...(urls.length === 1\n ? { image: { url: urls[0] } }\n : { images: urls.map((url) => ({ url })) }),\n ...(numberOfImages !== undefined && { n: numberOfImages }),\n ...imagineSizeParams(size),\n ...modelOptions,\n }\n\n try {\n logger.request(\n `activity=image provider=${this.name} model=${model} edit images=${urls.length}`,\n { provider: this.name, model },\n )\n\n const response = await fetch(\n `${this.clientConfig.baseURL}/images/edits`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.clientConfig.apiKey}`,\n },\n body: JSON.stringify(request),\n },\n )\n if (!response.ok) {\n const body = await response.text()\n throw new Error(\n `grok: image edit request failed (${response.status} ${response.statusText}): ${body}`,\n )\n }\n\n const result = (await response.json()) as GrokImageEditResponse\n const images: Array<GeneratedImage> = (result.data ?? []).flatMap(\n (item): Array<GeneratedImage> => {\n if (item.b64_json) return [{ b64Json: item.b64_json }]\n if (item.url) return [{ url: item.url }]\n return []\n },\n )\n if (images.length === 0) {\n throw new Error('grok: image edit response contained no images')\n }\n\n return {\n id: generateId(this.name),\n model,\n images,\n }\n } catch (error: unknown) {\n logger.errors(`${this.name}.generateImages fatal`, {\n error: toRunErrorPayload(error, `${this.name}.generateImages failed`),\n source: `${this.name}.generateImages`,\n })\n throw error\n }\n }\n}\n\n/**\n * Creates a Grok image adapter with explicit API key.\n * Type resolution happens here at the call site.\n *\n * @param model - The model name (e.g., 'grok-2-image-1212')\n * @param apiKey - Your xAI API key\n * @param config - Optional additional configuration\n * @returns Configured Grok image adapter instance with resolved types\n *\n * @example\n * ```typescript\n * const adapter = createGrokImage('grok-2-image-1212', \"xai-...\");\n *\n * const result = await generateImage({\n * adapter,\n * prompt: 'A cute baby sea otter'\n * });\n * ```\n */\nexport function createGrokImage<TModel extends GrokImageModel>(\n model: TModel,\n apiKey: string,\n config?: Omit<GrokImageConfig, 'apiKey'>,\n): GrokImageAdapter<TModel> {\n return new GrokImageAdapter({ apiKey, ...config }, model)\n}\n\n/**\n * Creates a Grok image adapter with automatic API key detection from environment variables.\n * Type resolution happens here at the call site.\n *\n * Looks for `XAI_API_KEY` in:\n * - `process.env` (Node.js)\n * - `window.env` (Browser with injected env)\n *\n * @param model - The model name (e.g., 'grok-2-image-1212')\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Grok image adapter instance with resolved types\n * @throws Error if XAI_API_KEY is not found in environment\n *\n * @example\n * ```typescript\n * // Automatically uses XAI_API_KEY from environment\n * const adapter = grokImage('grok-2-image-1212');\n *\n * const result = await generateImage({\n * adapter,\n * prompt: 'A beautiful sunset over mountains'\n * });\n * ```\n */\nexport function grokImage<TModel extends GrokImageModel>(\n model: TModel,\n config?: Omit<GrokImageConfig, 'apiKey'>,\n): GrokImageAdapter<TModel> {\n const apiKey = getGrokApiKeyFromEnv()\n return createGrokImage(model, apiKey, config)\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"image.js","names":[],"sources":["../../../src/adapters/image.ts"],"sourcesContent":["import OpenAI from 'openai'\nimport { resolveMediaPrompt } from '@tanstack/ai'\nimport { BaseImageAdapter } from '@tanstack/ai/adapters'\nimport { toRunErrorPayload } from '@tanstack/ai/adapter-internals'\nimport { buildImagesUsage } from '@tanstack/openai-base'\nimport { generateId } from '@tanstack/ai-utils'\nimport { getGrokApiKeyFromEnv, withGrokDefaults } from '../utils/client'\nimport {\n isGrokImagineImageModel,\n parseGrokImagineSize,\n validateImageSize,\n validateNumberOfImages,\n validatePrompt,\n} from '../image/image-provider-options'\nimport type {\n GeneratedImage,\n ImageGenerationOptions,\n ImageGenerationResult,\n ImagePart,\n MediaInputMetadata,\n ResolvedMediaPrompt,\n} from '@tanstack/ai'\nimport type OpenAI_SDK from 'openai'\nimport type { GrokImageModel } from '../model-meta'\nimport type {\n GrokImageModelInputModalitiesByName,\n GrokImageModelProviderOptionsByName,\n GrokImageModelSizeByName,\n GrokImageProviderOptions,\n} from '../image/image-provider-options'\nimport type { GrokClientConfig } from '../utils/client'\n\n/**\n * Configuration for Grok image adapter\n */\nexport interface GrokImageConfig extends GrokClientConfig {}\n\n/** Maximum source images accepted by xAI's image edit endpoint. */\nconst MAX_EDIT_IMAGES = 3\n\n/**\n * Maps the generic `size` option onto Imagine API parameters: the\n * \"aspectRatio_resolution\" template (\"16:9_2k\") splits into `aspect_ratio`\n * and optional `resolution` request fields.\n */\nfunction imagineSizeParams(size: string | undefined): {\n aspect_ratio?: string\n resolution?: string\n} {\n if (!size) return {}\n const parsed = parseGrokImagineSize(size)\n if (!parsed) return {}\n return {\n aspect_ratio: parsed.aspectRatio,\n ...(parsed.resolution !== undefined && { resolution: parsed.resolution }),\n }\n}\n\n/**\n * Convert a TanStack ImagePart to the URL string accepted by xAI's edit\n * endpoint: public URLs pass through (fetched by xAI's servers), data\n * sources become base64 data URIs.\n */\nfunction imagePartToUrl(part: ImagePart<MediaInputMetadata>): string {\n if (part.source.type === 'url') return part.source.value\n return `data:${part.source.mimeType};base64,${part.source.value}`\n}\n\n/** Response shape of xAI's `/v1/images/edits` endpoint. */\ninterface GrokImageEditResponse {\n data?: Array<{\n url?: string | null\n b64_json?: string | null\n mime_type?: string\n }>\n}\n\n/**\n * Grok Image Generation Adapter\n *\n * Tree-shakeable adapter for Grok image generation functionality.\n * Supports the legacy grok-2-image-1212 model (text-to-image via the\n * OpenAI-compat endpoint) and the grok-imagine image models, which also\n * accept image prompt parts for image-conditioned generation via xAI's\n * `/v1/images/edits` endpoint (up to 3 source images).\n *\n * Features:\n * - Model-specific type-safe provider options\n * - Size / aspect-ratio validation per model\n * - Number of images validation\n */\nexport class GrokImageAdapter<\n TModel extends GrokImageModel,\n> extends BaseImageAdapter<\n TModel,\n GrokImageProviderOptions,\n GrokImageModelProviderOptionsByName,\n GrokImageModelSizeByName,\n GrokImageModelInputModalitiesByName\n> {\n override readonly kind = 'image' as const\n readonly name = 'grok' as const\n\n protected client: OpenAI\n private readonly clientConfig: GrokImageConfig\n\n constructor(config: GrokImageConfig, model: TModel) {\n super(model, {})\n this.clientConfig = withGrokDefaults(config)\n this.client = new OpenAI(this.clientConfig)\n }\n\n async generateImages(\n options: ImageGenerationOptions<GrokImageProviderOptions>,\n ): Promise<ImageGenerationResult> {\n const { model, numberOfImages, size, modelOptions } = options\n\n const resolved = resolveMediaPrompt(options.prompt)\n const prompt = resolved.text\n\n if (resolved.videos.length > 0 || resolved.audios.length > 0) {\n throw new Error(\n `grok.generateImages does not support video / audio prompt parts on model ${model}.`,\n )\n }\n\n if (resolved.images.length > 0) {\n if (!isGrokImagineImageModel(model)) {\n throw new Error(\n `grok: model \"${model}\" does not support image prompt parts. ` +\n `Image-conditioned generation requires an Imagine API model ` +\n `('grok-imagine-image' or 'grok-imagine-image-quality').`,\n )\n }\n return await this.editImages(options, resolved)\n }\n\n validatePrompt({ prompt, model })\n validateImageSize(model, size)\n validateNumberOfImages(model, numberOfImages)\n\n // grok-imagine models are aspect-ratio sized: the generic `size` option\n // carries an \"aspectRatio_resolution\" template (e.g. '16:9_2k', like\n // Gemini native image models) and maps to the Imagine API's\n // `aspect_ratio` / `resolution` parameters instead of OpenAI-style `size`.\n const isImagine = isGrokImagineImageModel(model)\n const request = {\n model,\n prompt,\n n: numberOfImages ?? 1,\n ...(isImagine\n ? imagineSizeParams(size)\n : size !== undefined && {\n size: size,\n }),\n stream: false,\n ...modelOptions,\n } as OpenAI_SDK.Images.ImageGenerateParamsNonStreaming\n\n try {\n options.logger.request(\n `activity=image provider=${this.name} model=${model} n=${request.n ?? 1} size=${request.size ?? 'default'}`,\n { provider: this.name, model },\n )\n const response = await this.client.images.generate(request)\n\n const images: Array<GeneratedImage> = (response.data ?? []).flatMap(\n (item): Array<GeneratedImage> => {\n const revisedPrompt = item.revised_prompt\n if (item.b64_json) {\n return [\n {\n b64Json: item.b64_json,\n ...(revisedPrompt !== undefined && { revisedPrompt }),\n },\n ]\n }\n if (item.url) {\n return [\n {\n url: item.url,\n ...(revisedPrompt !== undefined && { revisedPrompt }),\n },\n ]\n }\n return []\n },\n )\n\n const usage = buildImagesUsage(response.usage)\n\n return {\n id: generateId(this.name),\n model,\n images,\n ...(usage ? { usage } : {}),\n }\n } catch (error: unknown) {\n options.logger.errors(`${this.name}.generateImages fatal`, {\n error: toRunErrorPayload(error, `${this.name}.generateImages failed`),\n source: `${this.name}.generateImages`,\n })\n throw error\n }\n }\n\n /**\n * Image-conditioned generation via xAI's Imagine API.\n *\n * The `/v1/images/edits` endpoint takes `application/json` (the OpenAI\n * SDK's `images.edit()` sends `multipart/form-data`, which xAI rejects),\n * so this path issues the request directly. One input is sent as\n * `image: { url }`; multiple inputs (up to 3) as `images: [{ url }, ...]`,\n * addressed by xAI in the order they are sent. The prompt text is sent\n * verbatim — no referencing markers are injected.\n */\n private async editImages(\n options: ImageGenerationOptions<GrokImageProviderOptions>,\n resolved: ResolvedMediaPrompt,\n ): Promise<ImageGenerationResult> {\n const { model, numberOfImages, size, modelOptions, logger } = options\n const prompt = resolved.text\n const imageInputs = resolved.images\n\n const unsupportedRole = imageInputs.find(\n (part) =>\n part.metadata?.role === 'mask' || part.metadata?.role === 'control',\n )\n if (unsupportedRole) {\n throw new Error(\n `grok: the Imagine API has no ${unsupportedRole.metadata?.role} input; ` +\n `only source/reference images are supported.`,\n )\n }\n if (imageInputs.length > MAX_EDIT_IMAGES) {\n throw new Error(\n `grok: model \"${model}\" accepts at most ${MAX_EDIT_IMAGES} source images; received ${imageInputs.length}.`,\n )\n }\n\n validatePrompt({ prompt, model })\n validateImageSize(model, size)\n validateNumberOfImages(model, numberOfImages)\n\n const urls = imageInputs.map((part) => imagePartToUrl(part))\n const request: Record<string, unknown> = {\n model,\n prompt,\n ...(urls.length === 1\n ? { image: { url: urls[0] } }\n : { images: urls.map((url) => ({ url })) }),\n ...(numberOfImages !== undefined && { n: numberOfImages }),\n ...imagineSizeParams(size),\n ...modelOptions,\n }\n\n try {\n logger.request(\n `activity=image provider=${this.name} model=${model} edit images=${urls.length}`,\n { provider: this.name, model },\n )\n\n const response = await fetch(\n `${this.clientConfig.baseURL}/images/edits`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.clientConfig.apiKey}`,\n },\n body: JSON.stringify(request),\n },\n )\n if (!response.ok) {\n const body = await response.text()\n throw new Error(\n `grok: image edit request failed (${response.status} ${response.statusText}): ${body}`,\n )\n }\n\n const result = (await response.json()) as GrokImageEditResponse\n const images: Array<GeneratedImage> = (result.data ?? []).flatMap(\n (item): Array<GeneratedImage> => {\n if (item.b64_json) return [{ b64Json: item.b64_json }]\n if (item.url) return [{ url: item.url }]\n return []\n },\n )\n if (images.length === 0) {\n throw new Error('grok: image edit response contained no images')\n }\n\n return {\n id: generateId(this.name),\n model,\n images,\n }\n } catch (error: unknown) {\n logger.errors(`${this.name}.generateImages fatal`, {\n error: toRunErrorPayload(error, `${this.name}.generateImages failed`),\n source: `${this.name}.generateImages`,\n })\n throw error\n }\n }\n}\n\n/**\n * Creates a Grok image adapter with explicit API key.\n * Type resolution happens here at the call site.\n *\n * @param model - The model name (e.g., 'grok-2-image-1212')\n * @param apiKey - Your xAI API key\n * @param config - Optional additional configuration\n * @returns Configured Grok image adapter instance with resolved types\n *\n * @example\n * ```typescript\n * const adapter = createGrokImage('grok-2-image-1212', \"xai-...\");\n *\n * const result = await generateImage({\n * adapter,\n * prompt: 'A cute baby sea otter'\n * });\n * ```\n */\nexport function createGrokImage<TModel extends GrokImageModel>(\n model: TModel,\n apiKey: string,\n config?: Omit<GrokImageConfig, 'apiKey'>,\n): GrokImageAdapter<TModel> {\n return new GrokImageAdapter({ apiKey, ...config }, model)\n}\n\n/**\n * Creates a Grok image adapter with automatic API key detection from environment variables.\n * Type resolution happens here at the call site.\n *\n * Looks for `XAI_API_KEY` in:\n * - `process.env` (Node.js)\n * - `window.env` (Browser with injected env)\n *\n * @param model - The model name (e.g., 'grok-2-image-1212')\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Grok image adapter instance with resolved types\n * @throws Error if XAI_API_KEY is not found in environment\n *\n * @example\n * ```typescript\n * // Automatically uses XAI_API_KEY from environment\n * const adapter = grokImage('grok-2-image-1212');\n *\n * const result = await generateImage({\n * adapter,\n * prompt: 'A beautiful sunset over mountains'\n * });\n * ```\n */\nexport function grokImage<TModel extends GrokImageModel>(\n model: TModel,\n config?: Omit<GrokImageConfig, 'apiKey'>,\n): GrokImageAdapter<TModel> {\n const apiKey = getGrokApiKeyFromEnv()\n return createGrokImage(model, apiKey, config)\n}\n"],"mappings":"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"}
|
|
@@ -1,18 +1,55 @@
|
|
|
1
|
-
import { ChatStreamSummarizeAdapter } from "@tanstack/ai/adapters";
|
|
2
1
|
import { getGrokApiKeyFromEnv } from "../utils/client.js";
|
|
3
2
|
import { GrokTextAdapter } from "./text.js";
|
|
3
|
+
import { ChatStreamSummarizeAdapter } from "@tanstack/ai/adapters";
|
|
4
|
+
//#region src/adapters/summarize.ts
|
|
5
|
+
/**
|
|
6
|
+
* Creates a Grok summarize adapter with explicit API key.
|
|
7
|
+
* Type resolution happens here at the call site.
|
|
8
|
+
*
|
|
9
|
+
* @param model - The model name (e.g., 'grok-build-0.1')
|
|
10
|
+
* @param apiKey - Your xAI API key
|
|
11
|
+
* @param config - Optional additional configuration
|
|
12
|
+
* @returns Configured Grok summarize adapter instance with resolved types
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const adapter = createGrokSummarize('grok-build-0.1', "xai-...");
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
4
19
|
function createGrokSummarize(model, apiKey, config) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
);
|
|
20
|
+
return new ChatStreamSummarizeAdapter(new GrokTextAdapter({
|
|
21
|
+
apiKey,
|
|
22
|
+
...config
|
|
23
|
+
}, model), model, "grok");
|
|
10
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Creates a Grok summarize adapter with automatic API key detection from environment variables.
|
|
27
|
+
* Type resolution happens here at the call site.
|
|
28
|
+
*
|
|
29
|
+
* Looks for `XAI_API_KEY` in:
|
|
30
|
+
* - `process.env` (Node.js)
|
|
31
|
+
* - `window.env` (Browser with injected env)
|
|
32
|
+
*
|
|
33
|
+
* @param model - The model name (e.g., 'grok-build-0.1')
|
|
34
|
+
* @param config - Optional configuration (excluding apiKey which is auto-detected)
|
|
35
|
+
* @returns Configured Grok summarize adapter instance with resolved types
|
|
36
|
+
* @throws Error if XAI_API_KEY is not found in environment
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* // Automatically uses XAI_API_KEY from environment
|
|
41
|
+
* const adapter = grokSummarize('grok-build-0.1');
|
|
42
|
+
*
|
|
43
|
+
* await summarize({
|
|
44
|
+
* adapter,
|
|
45
|
+
* text: "Long article text..."
|
|
46
|
+
* });
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
11
49
|
function grokSummarize(model, config) {
|
|
12
|
-
|
|
50
|
+
return createGrokSummarize(model, getGrokApiKeyFromEnv(), config);
|
|
13
51
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
//# sourceMappingURL=summarize.js.map
|
|
52
|
+
//#endregion
|
|
53
|
+
export { createGrokSummarize, grokSummarize };
|
|
54
|
+
|
|
55
|
+
//# sourceMappingURL=summarize.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarize.js","sources":["../../../src/adapters/summarize.ts"],"sourcesContent":["import { ChatStreamSummarizeAdapter } from '@tanstack/ai/adapters'\nimport { getGrokApiKeyFromEnv } from '../utils/client'\nimport { GrokTextAdapter } from './text'\nimport type { InferTextProviderOptions } from '@tanstack/ai/adapters'\nimport type { GROK_CHAT_MODELS } from '../model-meta'\nimport type { GrokClientConfig } from '../utils/client'\n\n/**\n * Configuration for Grok summarize adapter\n */\nexport interface GrokSummarizeConfig extends GrokClientConfig {}\n\n/** Model type for Grok summarization */\nexport type GrokSummarizeModel = (typeof GROK_CHAT_MODELS)[number]\n\n/**\n * Creates a Grok summarize adapter with explicit API key.\n * Type resolution happens here at the call site.\n *\n * @param model - The model name (e.g., 'grok-build-0.1')\n * @param apiKey - Your xAI API key\n * @param config - Optional additional configuration\n * @returns Configured Grok summarize adapter instance with resolved types\n *\n * @example\n * ```typescript\n * const adapter = createGrokSummarize('grok-build-0.1', \"xai-...\");\n * ```\n */\nexport function createGrokSummarize<TModel extends GrokSummarizeModel>(\n model: TModel,\n apiKey: string,\n config?: Omit<GrokSummarizeConfig, 'apiKey'>,\n): ChatStreamSummarizeAdapter<\n TModel,\n InferTextProviderOptions<GrokTextAdapter<TModel>>\n> {\n return new ChatStreamSummarizeAdapter(\n new GrokTextAdapter({ apiKey, ...config }, model),\n model,\n 'grok',\n )\n}\n\n/**\n * Creates a Grok summarize adapter with automatic API key detection from environment variables.\n * Type resolution happens here at the call site.\n *\n * Looks for `XAI_API_KEY` in:\n * - `process.env` (Node.js)\n * - `window.env` (Browser with injected env)\n *\n * @param model - The model name (e.g., 'grok-build-0.1')\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Grok summarize adapter instance with resolved types\n * @throws Error if XAI_API_KEY is not found in environment\n *\n * @example\n * ```typescript\n * // Automatically uses XAI_API_KEY from environment\n * const adapter = grokSummarize('grok-build-0.1');\n *\n * await summarize({\n * adapter,\n * text: \"Long article text...\"\n * });\n * ```\n */\nexport function grokSummarize<TModel extends GrokSummarizeModel>(\n model: TModel,\n config?: Omit<GrokSummarizeConfig, 'apiKey'>,\n): ChatStreamSummarizeAdapter<\n TModel,\n InferTextProviderOptions<GrokTextAdapter<TModel>>\n> {\n return createGrokSummarize(model, getGrokApiKeyFromEnv(), config)\n}\n"],"
|
|
1
|
+
{"version":3,"file":"summarize.js","names":[],"sources":["../../../src/adapters/summarize.ts"],"sourcesContent":["import { ChatStreamSummarizeAdapter } from '@tanstack/ai/adapters'\nimport { getGrokApiKeyFromEnv } from '../utils/client'\nimport { GrokTextAdapter } from './text'\nimport type { InferTextProviderOptions } from '@tanstack/ai/adapters'\nimport type { GROK_CHAT_MODELS } from '../model-meta'\nimport type { GrokClientConfig } from '../utils/client'\n\n/**\n * Configuration for Grok summarize adapter\n */\nexport interface GrokSummarizeConfig extends GrokClientConfig {}\n\n/** Model type for Grok summarization */\nexport type GrokSummarizeModel = (typeof GROK_CHAT_MODELS)[number]\n\n/**\n * Creates a Grok summarize adapter with explicit API key.\n * Type resolution happens here at the call site.\n *\n * @param model - The model name (e.g., 'grok-build-0.1')\n * @param apiKey - Your xAI API key\n * @param config - Optional additional configuration\n * @returns Configured Grok summarize adapter instance with resolved types\n *\n * @example\n * ```typescript\n * const adapter = createGrokSummarize('grok-build-0.1', \"xai-...\");\n * ```\n */\nexport function createGrokSummarize<TModel extends GrokSummarizeModel>(\n model: TModel,\n apiKey: string,\n config?: Omit<GrokSummarizeConfig, 'apiKey'>,\n): ChatStreamSummarizeAdapter<\n TModel,\n InferTextProviderOptions<GrokTextAdapter<TModel>>\n> {\n return new ChatStreamSummarizeAdapter(\n new GrokTextAdapter({ apiKey, ...config }, model),\n model,\n 'grok',\n )\n}\n\n/**\n * Creates a Grok summarize adapter with automatic API key detection from environment variables.\n * Type resolution happens here at the call site.\n *\n * Looks for `XAI_API_KEY` in:\n * - `process.env` (Node.js)\n * - `window.env` (Browser with injected env)\n *\n * @param model - The model name (e.g., 'grok-build-0.1')\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Grok summarize adapter instance with resolved types\n * @throws Error if XAI_API_KEY is not found in environment\n *\n * @example\n * ```typescript\n * // Automatically uses XAI_API_KEY from environment\n * const adapter = grokSummarize('grok-build-0.1');\n *\n * await summarize({\n * adapter,\n * text: \"Long article text...\"\n * });\n * ```\n */\nexport function grokSummarize<TModel extends GrokSummarizeModel>(\n model: TModel,\n config?: Omit<GrokSummarizeConfig, 'apiKey'>,\n): ChatStreamSummarizeAdapter<\n TModel,\n InferTextProviderOptions<GrokTextAdapter<TModel>>\n> {\n return createGrokSummarize(model, getGrokApiKeyFromEnv(), config)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA6BA,SAAgB,oBACd,OACA,QACA,QAIA;CACA,OAAO,IAAI,2BACT,IAAI,gBAAgB;EAAE;EAAQ,GAAG;CAAO,GAAG,KAAK,GAChD,OACA,MACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,cACd,OACA,QAIA;CACA,OAAO,oBAAoB,OAAO,qBAAqB,GAAG,MAAM;AAClE"}
|