@tanstack/ai-grok 0.7.2 → 0.8.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/dist/esm/adapters/image.d.ts +6 -8
- package/dist/esm/adapters/image.js +55 -9
- package/dist/esm/adapters/image.js.map +1 -1
- package/dist/esm/adapters/summarize.d.ts +4 -23
- package/dist/esm/adapters/summarize.js +8 -19
- package/dist/esm/adapters/summarize.js.map +1 -1
- package/dist/esm/adapters/text.d.ts +16 -5
- package/dist/esm/adapters/text.js +19 -3
- package/dist/esm/adapters/text.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -2
- package/dist/esm/utils/client.d.ts +4 -3
- package/dist/esm/utils/client.js.map +1 -1
- package/package.json +6 -5
- package/src/adapters/image.ts +71 -19
- package/src/adapters/summarize.ts +16 -46
- package/src/adapters/text.ts +27 -6
- package/src/index.ts +1 -3
- package/src/utils/client.ts +5 -5
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { default as OpenAI } from 'openai';
|
|
2
|
+
import { BaseImageAdapter } from '@tanstack/ai/adapters';
|
|
3
|
+
import { ImageGenerationOptions, ImageGenerationResult } from '@tanstack/ai';
|
|
2
4
|
import { GrokImageModel } from '../model-meta.js';
|
|
3
5
|
import { GrokImageModelProviderOptionsByName, GrokImageModelSizeByName, GrokImageProviderOptions } from '../image/image-provider-options.js';
|
|
4
6
|
import { GrokClientConfig } from '../utils.js';
|
|
@@ -18,16 +20,12 @@ export interface GrokImageConfig extends GrokClientConfig {
|
|
|
18
20
|
* - Size validation per model
|
|
19
21
|
* - Number of images validation
|
|
20
22
|
*/
|
|
21
|
-
export declare class GrokImageAdapter<TModel extends GrokImageModel> extends
|
|
23
|
+
export declare class GrokImageAdapter<TModel extends GrokImageModel> extends BaseImageAdapter<TModel, GrokImageProviderOptions, GrokImageModelProviderOptionsByName, GrokImageModelSizeByName> {
|
|
22
24
|
readonly kind: "image";
|
|
23
25
|
readonly name: "grok";
|
|
26
|
+
protected client: OpenAI;
|
|
24
27
|
constructor(config: GrokImageConfig, model: TModel);
|
|
25
|
-
|
|
26
|
-
prompt: string;
|
|
27
|
-
model: string;
|
|
28
|
-
}): void;
|
|
29
|
-
protected validateImageSize(model: string, size: string | undefined): void;
|
|
30
|
-
protected validateNumberOfImages(model: string, numberOfImages: number | undefined): void;
|
|
28
|
+
generateImages(options: ImageGenerationOptions<GrokImageProviderOptions>): Promise<ImageGenerationResult>;
|
|
31
29
|
}
|
|
32
30
|
/**
|
|
33
31
|
* Creates a Grok image adapter with explicit API key.
|
|
@@ -1,20 +1,66 @@
|
|
|
1
|
-
import
|
|
1
|
+
import OpenAI from "openai";
|
|
2
|
+
import { BaseImageAdapter } from "@tanstack/ai/adapters";
|
|
3
|
+
import { toRunErrorPayload } from "@tanstack/ai/adapter-internals";
|
|
4
|
+
import { generateId } from "@tanstack/ai-utils";
|
|
2
5
|
import { withGrokDefaults, getGrokApiKeyFromEnv } from "../utils/client.js";
|
|
3
6
|
import { validatePrompt, validateImageSize, validateNumberOfImages } from "../image/image-provider-options.js";
|
|
4
|
-
class GrokImageAdapter extends
|
|
7
|
+
class GrokImageAdapter extends BaseImageAdapter {
|
|
5
8
|
constructor(config, model) {
|
|
6
|
-
super(
|
|
9
|
+
super(model, {});
|
|
7
10
|
this.kind = "image";
|
|
8
11
|
this.name = "grok";
|
|
12
|
+
this.client = new OpenAI(withGrokDefaults(config));
|
|
9
13
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
validateImageSize(model, size) {
|
|
14
|
+
async generateImages(options) {
|
|
15
|
+
const { model, prompt, numberOfImages, size, modelOptions } = options;
|
|
16
|
+
validatePrompt({ prompt });
|
|
14
17
|
validateImageSize(model, size);
|
|
15
|
-
}
|
|
16
|
-
validateNumberOfImages(model, numberOfImages) {
|
|
17
18
|
validateNumberOfImages(model, numberOfImages);
|
|
19
|
+
const request = {
|
|
20
|
+
model,
|
|
21
|
+
prompt,
|
|
22
|
+
n: numberOfImages ?? 1,
|
|
23
|
+
size,
|
|
24
|
+
...modelOptions
|
|
25
|
+
};
|
|
26
|
+
try {
|
|
27
|
+
options.logger.request(
|
|
28
|
+
`activity=image provider=${this.name} model=${model} n=${request.n ?? 1} size=${request.size ?? "default"}`,
|
|
29
|
+
{ provider: this.name, model }
|
|
30
|
+
);
|
|
31
|
+
const response = await this.client.images.generate({
|
|
32
|
+
...request,
|
|
33
|
+
stream: false
|
|
34
|
+
});
|
|
35
|
+
const images = (response.data ?? []).flatMap(
|
|
36
|
+
(item) => {
|
|
37
|
+
const revisedPrompt = item.revised_prompt;
|
|
38
|
+
if (item.b64_json) {
|
|
39
|
+
return [{ b64Json: item.b64_json, revisedPrompt }];
|
|
40
|
+
}
|
|
41
|
+
if (item.url) {
|
|
42
|
+
return [{ url: item.url, revisedPrompt }];
|
|
43
|
+
}
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
return {
|
|
48
|
+
id: generateId(this.name),
|
|
49
|
+
model,
|
|
50
|
+
images,
|
|
51
|
+
usage: response.usage ? {
|
|
52
|
+
inputTokens: response.usage.input_tokens,
|
|
53
|
+
outputTokens: response.usage.output_tokens,
|
|
54
|
+
totalTokens: response.usage.total_tokens
|
|
55
|
+
} : void 0
|
|
56
|
+
};
|
|
57
|
+
} catch (error) {
|
|
58
|
+
options.logger.errors(`${this.name}.generateImages fatal`, {
|
|
59
|
+
error: toRunErrorPayload(error, `${this.name}.generateImages failed`),
|
|
60
|
+
source: `${this.name}.generateImages`
|
|
61
|
+
});
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
18
64
|
}
|
|
19
65
|
}
|
|
20
66
|
function createGrokImage(model, apiKey, config) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.js","sources":["../../../src/adapters/image.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"image.js","sources":["../../../src/adapters/image.ts"],"sourcesContent":["import OpenAI from 'openai'\nimport { BaseImageAdapter } from '@tanstack/ai/adapters'\nimport { toRunErrorPayload } from '@tanstack/ai/adapter-internals'\nimport { generateId } from '@tanstack/ai-utils'\nimport { getGrokApiKeyFromEnv, withGrokDefaults } from '../utils/client'\nimport {\n validateImageSize,\n validateNumberOfImages,\n validatePrompt,\n} from '../image/image-provider-options'\nimport type {\n GeneratedImage,\n ImageGenerationOptions,\n ImageGenerationResult,\n} from '@tanstack/ai'\nimport type OpenAI_SDK from 'openai'\nimport type { GrokImageModel } from '../model-meta'\nimport type {\n GrokImageModelProviderOptionsByName,\n GrokImageModelSizeByName,\n GrokImageProviderOptions,\n} from '../image/image-provider-options'\nimport type { GrokClientConfig } from '../utils'\n\n/**\n * Configuration for Grok image adapter\n */\nexport interface GrokImageConfig extends GrokClientConfig {}\n\n/**\n * Grok Image Generation Adapter\n *\n * Tree-shakeable adapter for Grok image generation functionality.\n * Supports grok-2-image-1212 model.\n *\n * Features:\n * - Model-specific type-safe provider options\n * - Size 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> {\n readonly kind = 'image' as const\n readonly name = 'grok' as const\n\n protected client: OpenAI\n\n constructor(config: GrokImageConfig, model: TModel) {\n super(model, {})\n this.client = new OpenAI(withGrokDefaults(config))\n }\n\n async generateImages(\n options: ImageGenerationOptions<GrokImageProviderOptions>,\n ): Promise<ImageGenerationResult> {\n const { model, prompt, numberOfImages, size, modelOptions } = options\n\n validatePrompt({ prompt, model })\n validateImageSize(model, size)\n validateNumberOfImages(model, numberOfImages)\n\n const request: OpenAI_SDK.Images.ImageGenerateParams = {\n model,\n prompt,\n n: numberOfImages ?? 1,\n size: size as OpenAI_SDK.Images.ImageGenerateParams['size'],\n ...modelOptions,\n }\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({\n ...request,\n stream: false,\n })\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 [{ b64Json: item.b64_json, revisedPrompt }]\n }\n if (item.url) {\n return [{ url: item.url, revisedPrompt }]\n }\n return []\n },\n )\n\n return {\n id: generateId(this.name),\n model,\n images,\n usage: response.usage\n ? {\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n totalTokens: response.usage.total_tokens,\n }\n : undefined,\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/**\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":";;;;;;AAwCO,MAAM,yBAEH,iBAKR;AAAA,EAMA,YAAY,QAAyB,OAAe;AAClD,UAAM,OAAO,EAAE;AANjB,SAAS,OAAO;AAChB,SAAS,OAAO;AAMd,SAAK,SAAS,IAAI,OAAO,iBAAiB,MAAM,CAAC;AAAA,EACnD;AAAA,EAEA,MAAM,eACJ,SACgC;AAChC,UAAM,EAAE,OAAO,QAAQ,gBAAgB,MAAM,iBAAiB;AAE9D,mBAAe,EAAE,OAAc,CAAC;AAChC,sBAAkB,OAAO,IAAI;AAC7B,2BAAuB,OAAO,cAAc;AAE5C,UAAM,UAAiD;AAAA,MACrD;AAAA,MACA;AAAA,MACA,GAAG,kBAAkB;AAAA,MACrB;AAAA,MACA,GAAG;AAAA,IAAA;AAGL,QAAI;AACF,cAAQ,OAAO;AAAA,QACb,2BAA2B,KAAK,IAAI,UAAU,KAAK,MAAM,QAAQ,KAAK,CAAC,SAAS,QAAQ,QAAQ,SAAS;AAAA,QACzG,EAAE,UAAU,KAAK,MAAM,MAAA;AAAA,MAAM;AAE/B,YAAM,WAAW,MAAM,KAAK,OAAO,OAAO,SAAS;AAAA,QACjD,GAAG;AAAA,QACH,QAAQ;AAAA,MAAA,CACT;AAED,YAAM,UAAiC,SAAS,QAAQ,CAAA,GAAI;AAAA,QAC1D,CAAC,SAAgC;AAC/B,gBAAM,gBAAgB,KAAK;AAC3B,cAAI,KAAK,UAAU;AACjB,mBAAO,CAAC,EAAE,SAAS,KAAK,UAAU,eAAe;AAAA,UACnD;AACA,cAAI,KAAK,KAAK;AACZ,mBAAO,CAAC,EAAE,KAAK,KAAK,KAAK,eAAe;AAAA,UAC1C;AACA,iBAAO,CAAA;AAAA,QACT;AAAA,MAAA;AAGF,aAAO;AAAA,QACL,IAAI,WAAW,KAAK,IAAI;AAAA,QACxB;AAAA,QACA;AAAA,QACA,OAAO,SAAS,QACZ;AAAA,UACE,aAAa,SAAS,MAAM;AAAA,UAC5B,cAAc,SAAS,MAAM;AAAA,UAC7B,aAAa,SAAS,MAAM;AAAA,QAAA,IAE9B;AAAA,MAAA;AAAA,IAER,SAAS,OAAgB;AACvB,cAAQ,OAAO,OAAO,GAAG,KAAK,IAAI,yBAAyB;AAAA,QACzD,OAAO,kBAAkB,OAAO,GAAG,KAAK,IAAI,wBAAwB;AAAA,QACpE,QAAQ,GAAG,KAAK,IAAI;AAAA,MAAA,CACrB;AACD,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAqBO,SAAS,gBACd,OACA,QACA,QAC0B;AAC1B,SAAO,IAAI,iBAAiB,EAAE,QAAQ,GAAG,OAAA,GAAU,KAAK;AAC1D;AA0BO,SAAS,UACd,OACA,QAC0B;AAC1B,QAAM,SAAS,qBAAA;AACf,SAAO,gBAAgB,OAAO,QAAQ,MAAM;AAC9C;"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChatStreamSummarizeAdapter, InferTextProviderOptions } from '@tanstack/ai/adapters';
|
|
2
|
+
import { GrokTextAdapter } from './text.js';
|
|
2
3
|
import { GROK_CHAT_MODELS } from '../model-meta.js';
|
|
3
4
|
import { GrokClientConfig } from '../utils.js';
|
|
4
5
|
/**
|
|
@@ -6,28 +7,8 @@ import { GrokClientConfig } from '../utils.js';
|
|
|
6
7
|
*/
|
|
7
8
|
export interface GrokSummarizeConfig extends GrokClientConfig {
|
|
8
9
|
}
|
|
9
|
-
/**
|
|
10
|
-
* Grok-specific provider options for summarization
|
|
11
|
-
*/
|
|
12
|
-
export interface GrokSummarizeProviderOptions {
|
|
13
|
-
/** Temperature for response generation (0-2) */
|
|
14
|
-
temperature?: number;
|
|
15
|
-
/** Maximum tokens in the response */
|
|
16
|
-
maxTokens?: number;
|
|
17
|
-
}
|
|
18
10
|
/** Model type for Grok summarization */
|
|
19
11
|
export type GrokSummarizeModel = (typeof GROK_CHAT_MODELS)[number];
|
|
20
|
-
/**
|
|
21
|
-
* Grok Summarize Adapter
|
|
22
|
-
*
|
|
23
|
-
* A thin wrapper around the text adapter that adds summarization-specific prompting.
|
|
24
|
-
* Delegates all API calls to the GrokTextAdapter.
|
|
25
|
-
*/
|
|
26
|
-
export declare class GrokSummarizeAdapter<TModel extends GrokSummarizeModel> extends OpenAICompatibleSummarizeAdapter<TModel, GrokSummarizeProviderOptions> {
|
|
27
|
-
readonly kind: "summarize";
|
|
28
|
-
readonly name: "grok";
|
|
29
|
-
constructor(config: GrokSummarizeConfig, model: TModel);
|
|
30
|
-
}
|
|
31
12
|
/**
|
|
32
13
|
* Creates a Grok summarize adapter with explicit API key.
|
|
33
14
|
* Type resolution happens here at the call site.
|
|
@@ -42,7 +23,7 @@ export declare class GrokSummarizeAdapter<TModel extends GrokSummarizeModel> ext
|
|
|
42
23
|
* const adapter = createGrokSummarize('grok-3', "xai-...");
|
|
43
24
|
* ```
|
|
44
25
|
*/
|
|
45
|
-
export declare function createGrokSummarize<TModel extends GrokSummarizeModel>(model: TModel, apiKey: string, config?: Omit<GrokSummarizeConfig, 'apiKey'>):
|
|
26
|
+
export declare function createGrokSummarize<TModel extends GrokSummarizeModel>(model: TModel, apiKey: string, config?: Omit<GrokSummarizeConfig, 'apiKey'>): ChatStreamSummarizeAdapter<TModel, InferTextProviderOptions<GrokTextAdapter<TModel>>>;
|
|
46
27
|
/**
|
|
47
28
|
* Creates a Grok summarize adapter with automatic API key detection from environment variables.
|
|
48
29
|
* Type resolution happens here at the call site.
|
|
@@ -67,4 +48,4 @@ export declare function createGrokSummarize<TModel extends GrokSummarizeModel>(m
|
|
|
67
48
|
* });
|
|
68
49
|
* ```
|
|
69
50
|
*/
|
|
70
|
-
export declare function grokSummarize<TModel extends GrokSummarizeModel>(model: TModel, config?: Omit<GrokSummarizeConfig, 'apiKey'>):
|
|
51
|
+
export declare function grokSummarize<TModel extends GrokSummarizeModel>(model: TModel, config?: Omit<GrokSummarizeConfig, 'apiKey'>): ChatStreamSummarizeAdapter<TModel, InferTextProviderOptions<GrokTextAdapter<TModel>>>;
|
|
@@ -1,30 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChatStreamSummarizeAdapter } from "@tanstack/ai/adapters";
|
|
2
2
|
import "@tanstack/ai-utils";
|
|
3
3
|
import { getGrokApiKeyFromEnv } from "../utils/client.js";
|
|
4
|
+
import "@tanstack/openai-base";
|
|
4
5
|
import { GrokTextAdapter } from "./text.js";
|
|
5
|
-
class GrokSummarizeAdapter extends OpenAICompatibleSummarizeAdapter {
|
|
6
|
-
constructor(config, model) {
|
|
7
|
-
super(
|
|
8
|
-
new GrokTextAdapter(
|
|
9
|
-
config,
|
|
10
|
-
model
|
|
11
|
-
),
|
|
12
|
-
model,
|
|
13
|
-
"grok"
|
|
14
|
-
);
|
|
15
|
-
this.kind = "summarize";
|
|
16
|
-
this.name = "grok";
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
6
|
function createGrokSummarize(model, apiKey, config) {
|
|
20
|
-
return new
|
|
7
|
+
return new ChatStreamSummarizeAdapter(
|
|
8
|
+
new GrokTextAdapter({ apiKey, ...config }, model),
|
|
9
|
+
model,
|
|
10
|
+
"grok"
|
|
11
|
+
);
|
|
21
12
|
}
|
|
22
13
|
function grokSummarize(model, config) {
|
|
23
|
-
|
|
24
|
-
return createGrokSummarize(model, apiKey, config);
|
|
14
|
+
return createGrokSummarize(model, getGrokApiKeyFromEnv(), config);
|
|
25
15
|
}
|
|
26
16
|
export {
|
|
27
|
-
GrokSummarizeAdapter,
|
|
28
17
|
createGrokSummarize,
|
|
29
18
|
grokSummarize
|
|
30
19
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarize.js","sources":["../../../src/adapters/summarize.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"summarize.js","sources":["../../../src/adapters/summarize.ts"],"sourcesContent":["import { ChatStreamSummarizeAdapter } from '@tanstack/ai/adapters'\nimport { getGrokApiKeyFromEnv } from '../utils'\nimport { GrokTextAdapter } from './text'\nimport type { InferTextProviderOptions } from '@tanstack/ai/adapters'\nimport type { GROK_CHAT_MODELS } from '../model-meta'\nimport type { GrokClientConfig } from '../utils'\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-3', 'grok-4')\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-3', \"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-3', 'grok-4')\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-3');\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"],"names":[],"mappings":";;;;;AA6BO,SAAS,oBACd,OACA,QACA,QAIA;AACA,SAAO,IAAI;AAAA,IACT,IAAI,gBAAgB,EAAE,QAAQ,GAAG,OAAA,GAAU,KAAK;AAAA,IAChD;AAAA,IACA;AAAA,EAAA;AAEJ;AA0BO,SAAS,cACd,OACA,QAIA;AACA,SAAO,oBAAoB,OAAO,qBAAA,GAAwB,MAAM;AAClE;"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { default as OpenAI } from 'openai';
|
|
2
|
+
import { OpenAIBaseChatCompletionsTextAdapter } from '@tanstack/openai-base';
|
|
2
3
|
import { GROK_CHAT_MODELS, GrokChatModelToolCapabilitiesByName, ResolveInputModalities, ResolveProviderOptions } from '../model-meta.js';
|
|
3
4
|
import { Modality } from '@tanstack/ai';
|
|
4
5
|
import { GrokMessageMetadataByModality } from '../message-types.js';
|
|
@@ -22,14 +23,24 @@ export type { ExternalTextProviderOptions as GrokTextProviderOptions } from '../
|
|
|
22
23
|
* Tree-shakeable adapter for Grok chat/text completion functionality.
|
|
23
24
|
* Uses OpenAI-compatible Chat Completions API (not Responses API).
|
|
24
25
|
*
|
|
25
|
-
* Delegates implementation to {@link
|
|
26
|
-
* from `@tanstack/openai-base` and threads Grok-specific tool-capability
|
|
27
|
-
* through the 5th generic of the base class.
|
|
26
|
+
* Delegates implementation to {@link OpenAIBaseChatCompletionsTextAdapter}
|
|
27
|
+
* from `@tanstack/openai-base` and threads Grok-specific tool-capability
|
|
28
|
+
* typing through the 5th generic of the base class.
|
|
28
29
|
*/
|
|
29
|
-
export declare class GrokTextAdapter<TModel extends (typeof GROK_CHAT_MODELS)[number], TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>, TInputModalities extends ReadonlyArray<Modality> = ResolveInputModalities<TModel>, TToolCapabilities extends ReadonlyArray<string> = ResolveToolCapabilities<TModel>> extends
|
|
30
|
+
export declare class GrokTextAdapter<TModel extends (typeof GROK_CHAT_MODELS)[number], TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>, TInputModalities extends ReadonlyArray<Modality> = ResolveInputModalities<TModel>, TToolCapabilities extends ReadonlyArray<string> = ResolveToolCapabilities<TModel>> extends OpenAIBaseChatCompletionsTextAdapter<TModel, TProviderOptions, TInputModalities, GrokMessageMetadataByModality, TToolCapabilities> {
|
|
30
31
|
readonly kind: "text";
|
|
31
32
|
readonly name: "grok";
|
|
32
33
|
constructor(config: GrokTextConfig, model: TModel);
|
|
34
|
+
/**
|
|
35
|
+
* Surfaces xAI reasoning deltas on Grok reasoning models. The DeepSeek-style
|
|
36
|
+
* convention puts the chain-of-thought on `delta.reasoning_content`; some
|
|
37
|
+
* Grok variants also populate `delta.reasoning`. Reading both keeps
|
|
38
|
+
* reasoning flowing through the base's REASONING_* lifecycle for both
|
|
39
|
+
* `chatStream` and `structuredOutputStream`.
|
|
40
|
+
*/
|
|
41
|
+
protected extractReasoning(chunk: OpenAI.Chat.Completions.ChatCompletionChunk): {
|
|
42
|
+
text: string;
|
|
43
|
+
} | undefined;
|
|
33
44
|
}
|
|
34
45
|
/**
|
|
35
46
|
* Creates a Grok text adapter with explicit API key.
|
|
@@ -1,11 +1,27 @@
|
|
|
1
|
-
import
|
|
1
|
+
import OpenAI from "openai";
|
|
2
|
+
import { OpenAIBaseChatCompletionsTextAdapter } from "@tanstack/openai-base";
|
|
2
3
|
import { withGrokDefaults, getGrokApiKeyFromEnv } from "../utils/client.js";
|
|
3
|
-
class GrokTextAdapter extends
|
|
4
|
+
class GrokTextAdapter extends OpenAIBaseChatCompletionsTextAdapter {
|
|
4
5
|
constructor(config, model) {
|
|
5
|
-
super(
|
|
6
|
+
super(model, "grok", new OpenAI(withGrokDefaults(config)));
|
|
6
7
|
this.kind = "text";
|
|
7
8
|
this.name = "grok";
|
|
8
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Surfaces xAI reasoning deltas on Grok reasoning models. The DeepSeek-style
|
|
12
|
+
* convention puts the chain-of-thought on `delta.reasoning_content`; some
|
|
13
|
+
* Grok variants also populate `delta.reasoning`. Reading both keeps
|
|
14
|
+
* reasoning flowing through the base's REASONING_* lifecycle for both
|
|
15
|
+
* `chatStream` and `structuredOutputStream`.
|
|
16
|
+
*/
|
|
17
|
+
extractReasoning(chunk) {
|
|
18
|
+
const delta = chunk.choices[0]?.delta;
|
|
19
|
+
const raw = delta?.reasoning_content ?? delta?.reasoning;
|
|
20
|
+
if (typeof raw === "string" && raw.length > 0) {
|
|
21
|
+
return { text: raw };
|
|
22
|
+
}
|
|
23
|
+
return void 0;
|
|
24
|
+
}
|
|
9
25
|
}
|
|
10
26
|
function createGrokText(model, apiKey, config) {
|
|
11
27
|
return new GrokTextAdapter({ apiKey, ...config }, model);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.js","sources":["../../../src/adapters/text.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"text.js","sources":["../../../src/adapters/text.ts"],"sourcesContent":["import OpenAI from 'openai'\nimport { OpenAIBaseChatCompletionsTextAdapter } from '@tanstack/openai-base'\nimport { getGrokApiKeyFromEnv, withGrokDefaults } from '../utils/client'\nimport type {\n GROK_CHAT_MODELS,\n GrokChatModelToolCapabilitiesByName,\n ResolveInputModalities,\n ResolveProviderOptions,\n} from '../model-meta'\nimport type { Modality } from '@tanstack/ai'\nimport type { GrokMessageMetadataByModality } from '../message-types'\nimport type { GrokClientConfig } from '../utils'\n\n/**\n * Resolve tool capabilities for a specific Grok model.\n */\ntype ResolveToolCapabilities<TModel extends string> =\n TModel extends keyof GrokChatModelToolCapabilitiesByName\n ? NonNullable<GrokChatModelToolCapabilitiesByName[TModel]>\n : readonly []\n\n/**\n * Configuration for Grok text adapter\n */\nexport interface GrokTextConfig extends GrokClientConfig {}\n\n/**\n * Alias for TextProviderOptions for external use\n */\nexport type { ExternalTextProviderOptions as GrokTextProviderOptions } from '../text/text-provider-options'\n\n/**\n * Grok Text (Chat) Adapter\n *\n * Tree-shakeable adapter for Grok chat/text completion functionality.\n * Uses OpenAI-compatible Chat Completions API (not Responses API).\n *\n * Delegates implementation to {@link OpenAIBaseChatCompletionsTextAdapter}\n * from `@tanstack/openai-base` and threads Grok-specific tool-capability\n * typing through the 5th generic of the base class.\n */\nexport class GrokTextAdapter<\n TModel extends (typeof GROK_CHAT_MODELS)[number],\n TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>,\n TInputModalities extends ReadonlyArray<Modality> =\n ResolveInputModalities<TModel>,\n TToolCapabilities extends ReadonlyArray<string> =\n ResolveToolCapabilities<TModel>,\n> extends OpenAIBaseChatCompletionsTextAdapter<\n TModel,\n TProviderOptions,\n TInputModalities,\n GrokMessageMetadataByModality,\n TToolCapabilities\n> {\n readonly kind = 'text' as const\n readonly name = 'grok' as const\n\n constructor(config: GrokTextConfig, model: TModel) {\n super(model, 'grok', new OpenAI(withGrokDefaults(config)))\n }\n\n /**\n * Surfaces xAI reasoning deltas on Grok reasoning models. The DeepSeek-style\n * convention puts the chain-of-thought on `delta.reasoning_content`; some\n * Grok variants also populate `delta.reasoning`. Reading both keeps\n * reasoning flowing through the base's REASONING_* lifecycle for both\n * `chatStream` and `structuredOutputStream`.\n */\n protected override extractReasoning(\n chunk: OpenAI.Chat.Completions.ChatCompletionChunk,\n ): { text: string } | undefined {\n const delta = chunk.choices[0]?.delta as\n | { reasoning?: unknown; reasoning_content?: unknown }\n | undefined\n const raw = delta?.reasoning_content ?? delta?.reasoning\n if (typeof raw === 'string' && raw.length > 0) {\n return { text: raw }\n }\n return undefined\n }\n}\n\n/**\n * Creates a Grok text adapter with explicit API key.\n * Type resolution happens here at the call site.\n *\n * @param model - The model name (e.g., 'grok-3', 'grok-4')\n * @param apiKey - Your xAI API key\n * @param config - Optional additional configuration\n * @returns Configured Grok text adapter instance with resolved types\n *\n * @example\n * ```typescript\n * const adapter = createGrokText('grok-3', \"xai-...\");\n * // adapter has type-safe providerOptions for grok-3\n * ```\n */\nexport function createGrokText<\n TModel extends (typeof GROK_CHAT_MODELS)[number],\n>(\n model: TModel,\n apiKey: string,\n config?: Omit<GrokTextConfig, 'apiKey'>,\n): GrokTextAdapter<TModel> {\n return new GrokTextAdapter({ apiKey, ...config }, model)\n}\n\n/**\n * Creates a Grok text 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-3', 'grok-4')\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Grok text 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 = grokText('grok-3');\n *\n * const stream = chat({\n * adapter,\n * messages: [{ role: \"user\", content: \"Hello!\" }]\n * });\n * ```\n */\nexport function grokText<TModel extends (typeof GROK_CHAT_MODELS)[number]>(\n model: TModel,\n config?: Omit<GrokTextConfig, 'apiKey'>,\n): GrokTextAdapter<TModel> {\n const apiKey = getGrokApiKeyFromEnv()\n return createGrokText(model, apiKey, config)\n}\n"],"names":[],"mappings":";;;AAyCO,MAAM,wBAOH,qCAMR;AAAA,EAIA,YAAY,QAAwB,OAAe;AACjD,UAAM,OAAO,QAAQ,IAAI,OAAO,iBAAiB,MAAM,CAAC,CAAC;AAJ3D,SAAS,OAAO;AAChB,SAAS,OAAO;AAAA,EAIhB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASmB,iBACjB,OAC8B;AAC9B,UAAM,QAAQ,MAAM,QAAQ,CAAC,GAAG;AAGhC,UAAM,MAAM,OAAO,qBAAqB,OAAO;AAC/C,QAAI,OAAO,QAAQ,YAAY,IAAI,SAAS,GAAG;AAC7C,aAAO,EAAE,MAAM,IAAA;AAAA,IACjB;AACA,WAAO;AAAA,EACT;AACF;AAiBO,SAAS,eAGd,OACA,QACA,QACyB;AACzB,SAAO,IAAI,gBAAgB,EAAE,QAAQ,GAAG,OAAA,GAAU,KAAK;AACzD;AA0BO,SAAS,SACd,OACA,QACyB;AACzB,QAAM,SAAS,qBAAA;AACf,SAAO,eAAe,OAAO,QAAQ,MAAM;AAC7C;"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { GrokTextAdapter, createGrokText, grokText, type GrokTextConfig, type GrokTextProviderOptions, } from './adapters/text.js';
|
|
2
|
-
export {
|
|
2
|
+
export { createGrokSummarize, grokSummarize, type GrokSummarizeConfig, type GrokSummarizeModel, } from './adapters/summarize.js';
|
|
3
3
|
export { GrokImageAdapter, createGrokImage, grokImage, type GrokImageConfig, } from './adapters/image.js';
|
|
4
4
|
export type { GrokImageProviderOptions, GrokImageModelProviderOptionsByName, } from './image/image-provider-options.js';
|
|
5
5
|
export { GrokSpeechAdapter, createGrokSpeech, grokSpeech, type GrokSpeechConfig, } from './adapters/tts.js';
|
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GrokTextAdapter, createGrokText, grokText } from "./adapters/text.js";
|
|
2
|
-
import {
|
|
2
|
+
import { createGrokSummarize, grokSummarize } from "./adapters/summarize.js";
|
|
3
3
|
import { GrokImageAdapter, createGrokImage, grokImage } from "./adapters/image.js";
|
|
4
4
|
import { GrokSpeechAdapter, createGrokSpeech, grokSpeech } from "./adapters/tts.js";
|
|
5
5
|
import { GrokTranscriptionAdapter, createGrokTranscription, grokTranscription } from "./adapters/transcription.js";
|
|
@@ -14,7 +14,6 @@ export {
|
|
|
14
14
|
GROK_TTS_MODELS,
|
|
15
15
|
GrokImageAdapter,
|
|
16
16
|
GrokSpeechAdapter,
|
|
17
|
-
GrokSummarizeAdapter,
|
|
18
17
|
GrokTextAdapter,
|
|
19
18
|
GrokTranscriptionAdapter,
|
|
20
19
|
createGrokImage,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export interface GrokClientConfig extends
|
|
1
|
+
import { ClientOptions } from 'openai';
|
|
2
|
+
export interface GrokClientConfig extends Omit<ClientOptions, 'apiKey'> {
|
|
3
|
+
apiKey: string;
|
|
3
4
|
}
|
|
4
5
|
/**
|
|
5
6
|
* Gets Grok API key from environment variables
|
|
@@ -10,4 +11,4 @@ export declare function getGrokApiKeyFromEnv(): string;
|
|
|
10
11
|
* Returns a Grok client config with the default xAI base URL applied
|
|
11
12
|
* when not already set.
|
|
12
13
|
*/
|
|
13
|
-
export declare function withGrokDefaults(config: GrokClientConfig):
|
|
14
|
+
export declare function withGrokDefaults(config: GrokClientConfig): GrokClientConfig;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sources":["../../../src/utils/client.ts"],"sourcesContent":["import { getApiKeyFromEnv } from '@tanstack/ai-utils'\nimport type {
|
|
1
|
+
{"version":3,"file":"client.js","sources":["../../../src/utils/client.ts"],"sourcesContent":["import { getApiKeyFromEnv } from '@tanstack/ai-utils'\nimport type { ClientOptions } from 'openai'\n\nexport interface GrokClientConfig extends Omit<ClientOptions, 'apiKey'> {\n apiKey: string\n}\n\n/**\n * Gets Grok API key from environment variables\n * @throws Error if XAI_API_KEY is not found\n */\nexport function getGrokApiKeyFromEnv(): string {\n try {\n return getApiKeyFromEnv('XAI_API_KEY')\n } catch {\n throw new Error(\n 'XAI_API_KEY is required. Please set it in your environment variables or use the factory function with an explicit API key.',\n )\n }\n}\n\n/**\n * Returns a Grok client config with the default xAI base URL applied\n * when not already set.\n */\nexport function withGrokDefaults(config: GrokClientConfig): GrokClientConfig {\n return {\n ...config,\n baseURL: config.baseURL || 'https://api.x.ai/v1',\n }\n}\n"],"names":[],"mappings":";AAWO,SAAS,uBAA+B;AAC7C,MAAI;AACF,WAAO,iBAAiB,aAAa;AAAA,EACvC,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAEJ;AACF;AAMO,SAAS,iBAAiB,QAA4C;AAC3E,SAAO;AAAA,IACL,GAAG;AAAA,IACH,SAAS,OAAO,WAAW;AAAA,EAAA;AAE/B;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/ai-grok",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Grok (xAI) adapter for TanStack AI",
|
|
5
5
|
"author": "",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,18 +34,19 @@
|
|
|
34
34
|
"adapter"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
+
"openai": "^6.9.1",
|
|
37
38
|
"@tanstack/ai-utils": "0.2.0",
|
|
38
|
-
"@tanstack/openai-base": "0.
|
|
39
|
+
"@tanstack/openai-base": "0.3.0"
|
|
39
40
|
},
|
|
40
41
|
"devDependencies": {
|
|
41
42
|
"@vitest/coverage-v8": "4.0.14",
|
|
42
43
|
"vite": "^7.2.7",
|
|
43
|
-
"@tanstack/ai": "0.
|
|
44
|
-
"@tanstack/ai-client": "0.9.
|
|
44
|
+
"@tanstack/ai": "0.17.0",
|
|
45
|
+
"@tanstack/ai-client": "0.9.2"
|
|
45
46
|
},
|
|
46
47
|
"peerDependencies": {
|
|
47
48
|
"zod": "^4.0.0",
|
|
48
|
-
"@tanstack/ai": "^0.
|
|
49
|
+
"@tanstack/ai": "^0.17.0"
|
|
49
50
|
},
|
|
50
51
|
"scripts": {
|
|
51
52
|
"build": "vite build",
|
package/src/adapters/image.ts
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
|
-
import
|
|
1
|
+
import OpenAI from 'openai'
|
|
2
|
+
import { BaseImageAdapter } from '@tanstack/ai/adapters'
|
|
3
|
+
import { toRunErrorPayload } from '@tanstack/ai/adapter-internals'
|
|
4
|
+
import { generateId } from '@tanstack/ai-utils'
|
|
2
5
|
import { getGrokApiKeyFromEnv, withGrokDefaults } from '../utils/client'
|
|
3
6
|
import {
|
|
4
7
|
validateImageSize,
|
|
5
8
|
validateNumberOfImages,
|
|
6
9
|
validatePrompt,
|
|
7
10
|
} from '../image/image-provider-options'
|
|
11
|
+
import type {
|
|
12
|
+
GeneratedImage,
|
|
13
|
+
ImageGenerationOptions,
|
|
14
|
+
ImageGenerationResult,
|
|
15
|
+
} from '@tanstack/ai'
|
|
16
|
+
import type OpenAI_SDK from 'openai'
|
|
8
17
|
import type { GrokImageModel } from '../model-meta'
|
|
9
18
|
import type {
|
|
10
19
|
GrokImageModelProviderOptionsByName,
|
|
@@ -31,7 +40,7 @@ export interface GrokImageConfig extends GrokClientConfig {}
|
|
|
31
40
|
*/
|
|
32
41
|
export class GrokImageAdapter<
|
|
33
42
|
TModel extends GrokImageModel,
|
|
34
|
-
> extends
|
|
43
|
+
> extends BaseImageAdapter<
|
|
35
44
|
TModel,
|
|
36
45
|
GrokImageProviderOptions,
|
|
37
46
|
GrokImageModelProviderOptionsByName,
|
|
@@ -40,29 +49,72 @@ export class GrokImageAdapter<
|
|
|
40
49
|
readonly kind = 'image' as const
|
|
41
50
|
readonly name = 'grok' as const
|
|
42
51
|
|
|
52
|
+
protected client: OpenAI
|
|
53
|
+
|
|
43
54
|
constructor(config: GrokImageConfig, model: TModel) {
|
|
44
|
-
super(
|
|
55
|
+
super(model, {})
|
|
56
|
+
this.client = new OpenAI(withGrokDefaults(config))
|
|
45
57
|
}
|
|
46
58
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
validatePrompt(options)
|
|
52
|
-
}
|
|
59
|
+
async generateImages(
|
|
60
|
+
options: ImageGenerationOptions<GrokImageProviderOptions>,
|
|
61
|
+
): Promise<ImageGenerationResult> {
|
|
62
|
+
const { model, prompt, numberOfImages, size, modelOptions } = options
|
|
53
63
|
|
|
54
|
-
|
|
55
|
-
model: string,
|
|
56
|
-
size: string | undefined,
|
|
57
|
-
): void {
|
|
64
|
+
validatePrompt({ prompt, model })
|
|
58
65
|
validateImageSize(model, size)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
protected override validateNumberOfImages(
|
|
62
|
-
model: string,
|
|
63
|
-
numberOfImages: number | undefined,
|
|
64
|
-
): void {
|
|
65
66
|
validateNumberOfImages(model, numberOfImages)
|
|
67
|
+
|
|
68
|
+
const request: OpenAI_SDK.Images.ImageGenerateParams = {
|
|
69
|
+
model,
|
|
70
|
+
prompt,
|
|
71
|
+
n: numberOfImages ?? 1,
|
|
72
|
+
size: size as OpenAI_SDK.Images.ImageGenerateParams['size'],
|
|
73
|
+
...modelOptions,
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
options.logger.request(
|
|
78
|
+
`activity=image provider=${this.name} model=${model} n=${request.n ?? 1} size=${request.size ?? 'default'}`,
|
|
79
|
+
{ provider: this.name, model },
|
|
80
|
+
)
|
|
81
|
+
const response = await this.client.images.generate({
|
|
82
|
+
...request,
|
|
83
|
+
stream: false,
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
const images: Array<GeneratedImage> = (response.data ?? []).flatMap(
|
|
87
|
+
(item): Array<GeneratedImage> => {
|
|
88
|
+
const revisedPrompt = item.revised_prompt
|
|
89
|
+
if (item.b64_json) {
|
|
90
|
+
return [{ b64Json: item.b64_json, revisedPrompt }]
|
|
91
|
+
}
|
|
92
|
+
if (item.url) {
|
|
93
|
+
return [{ url: item.url, revisedPrompt }]
|
|
94
|
+
}
|
|
95
|
+
return []
|
|
96
|
+
},
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
id: generateId(this.name),
|
|
101
|
+
model,
|
|
102
|
+
images,
|
|
103
|
+
usage: response.usage
|
|
104
|
+
? {
|
|
105
|
+
inputTokens: response.usage.input_tokens,
|
|
106
|
+
outputTokens: response.usage.output_tokens,
|
|
107
|
+
totalTokens: response.usage.total_tokens,
|
|
108
|
+
}
|
|
109
|
+
: undefined,
|
|
110
|
+
}
|
|
111
|
+
} catch (error: unknown) {
|
|
112
|
+
options.logger.errors(`${this.name}.generateImages fatal`, {
|
|
113
|
+
error: toRunErrorPayload(error, `${this.name}.generateImages failed`),
|
|
114
|
+
source: `${this.name}.generateImages`,
|
|
115
|
+
})
|
|
116
|
+
throw error
|
|
117
|
+
}
|
|
66
118
|
}
|
|
67
119
|
}
|
|
68
120
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChatStreamSummarizeAdapter } from '@tanstack/ai/adapters'
|
|
2
2
|
import { getGrokApiKeyFromEnv } from '../utils'
|
|
3
3
|
import { GrokTextAdapter } from './text'
|
|
4
|
-
import type {
|
|
4
|
+
import type { InferTextProviderOptions } from '@tanstack/ai/adapters'
|
|
5
5
|
import type { GROK_CHAT_MODELS } from '../model-meta'
|
|
6
6
|
import type { GrokClientConfig } from '../utils'
|
|
7
7
|
|
|
@@ -10,48 +10,9 @@ import type { GrokClientConfig } from '../utils'
|
|
|
10
10
|
*/
|
|
11
11
|
export interface GrokSummarizeConfig extends GrokClientConfig {}
|
|
12
12
|
|
|
13
|
-
/**
|
|
14
|
-
* Grok-specific provider options for summarization
|
|
15
|
-
*/
|
|
16
|
-
export interface GrokSummarizeProviderOptions {
|
|
17
|
-
/** Temperature for response generation (0-2) */
|
|
18
|
-
temperature?: number
|
|
19
|
-
/** Maximum tokens in the response */
|
|
20
|
-
maxTokens?: number
|
|
21
|
-
}
|
|
22
|
-
|
|
23
13
|
/** Model type for Grok summarization */
|
|
24
14
|
export type GrokSummarizeModel = (typeof GROK_CHAT_MODELS)[number]
|
|
25
15
|
|
|
26
|
-
/**
|
|
27
|
-
* Grok Summarize Adapter
|
|
28
|
-
*
|
|
29
|
-
* A thin wrapper around the text adapter that adds summarization-specific prompting.
|
|
30
|
-
* Delegates all API calls to the GrokTextAdapter.
|
|
31
|
-
*/
|
|
32
|
-
export class GrokSummarizeAdapter<
|
|
33
|
-
TModel extends GrokSummarizeModel,
|
|
34
|
-
> extends OpenAICompatibleSummarizeAdapter<
|
|
35
|
-
TModel,
|
|
36
|
-
GrokSummarizeProviderOptions
|
|
37
|
-
> {
|
|
38
|
-
readonly kind = 'summarize' as const
|
|
39
|
-
readonly name = 'grok' as const
|
|
40
|
-
|
|
41
|
-
constructor(config: GrokSummarizeConfig, model: TModel) {
|
|
42
|
-
// The text adapter accepts richer provider options than the summarize adapter needs,
|
|
43
|
-
// but we only pass basic options (model, messages, systemPrompts, etc.) at call time.
|
|
44
|
-
super(
|
|
45
|
-
new GrokTextAdapter(
|
|
46
|
-
config,
|
|
47
|
-
model,
|
|
48
|
-
) as unknown as ChatStreamCapable<GrokSummarizeProviderOptions>,
|
|
49
|
-
model,
|
|
50
|
-
'grok',
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
16
|
/**
|
|
56
17
|
* Creates a Grok summarize adapter with explicit API key.
|
|
57
18
|
* Type resolution happens here at the call site.
|
|
@@ -70,8 +31,15 @@ export function createGrokSummarize<TModel extends GrokSummarizeModel>(
|
|
|
70
31
|
model: TModel,
|
|
71
32
|
apiKey: string,
|
|
72
33
|
config?: Omit<GrokSummarizeConfig, 'apiKey'>,
|
|
73
|
-
):
|
|
74
|
-
|
|
34
|
+
): ChatStreamSummarizeAdapter<
|
|
35
|
+
TModel,
|
|
36
|
+
InferTextProviderOptions<GrokTextAdapter<TModel>>
|
|
37
|
+
> {
|
|
38
|
+
return new ChatStreamSummarizeAdapter(
|
|
39
|
+
new GrokTextAdapter({ apiKey, ...config }, model),
|
|
40
|
+
model,
|
|
41
|
+
'grok',
|
|
42
|
+
)
|
|
75
43
|
}
|
|
76
44
|
|
|
77
45
|
/**
|
|
@@ -101,7 +69,9 @@ export function createGrokSummarize<TModel extends GrokSummarizeModel>(
|
|
|
101
69
|
export function grokSummarize<TModel extends GrokSummarizeModel>(
|
|
102
70
|
model: TModel,
|
|
103
71
|
config?: Omit<GrokSummarizeConfig, 'apiKey'>,
|
|
104
|
-
):
|
|
105
|
-
|
|
106
|
-
|
|
72
|
+
): ChatStreamSummarizeAdapter<
|
|
73
|
+
TModel,
|
|
74
|
+
InferTextProviderOptions<GrokTextAdapter<TModel>>
|
|
75
|
+
> {
|
|
76
|
+
return createGrokSummarize(model, getGrokApiKeyFromEnv(), config)
|
|
107
77
|
}
|
package/src/adapters/text.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import OpenAI from 'openai'
|
|
2
|
+
import { OpenAIBaseChatCompletionsTextAdapter } from '@tanstack/openai-base'
|
|
2
3
|
import { getGrokApiKeyFromEnv, withGrokDefaults } from '../utils/client'
|
|
3
4
|
import type {
|
|
4
5
|
GROK_CHAT_MODELS,
|
|
@@ -34,9 +35,9 @@ export type { ExternalTextProviderOptions as GrokTextProviderOptions } from '../
|
|
|
34
35
|
* Tree-shakeable adapter for Grok chat/text completion functionality.
|
|
35
36
|
* Uses OpenAI-compatible Chat Completions API (not Responses API).
|
|
36
37
|
*
|
|
37
|
-
* Delegates implementation to {@link
|
|
38
|
-
* from `@tanstack/openai-base` and threads Grok-specific tool-capability
|
|
39
|
-
* through the 5th generic of the base class.
|
|
38
|
+
* Delegates implementation to {@link OpenAIBaseChatCompletionsTextAdapter}
|
|
39
|
+
* from `@tanstack/openai-base` and threads Grok-specific tool-capability
|
|
40
|
+
* typing through the 5th generic of the base class.
|
|
40
41
|
*/
|
|
41
42
|
export class GrokTextAdapter<
|
|
42
43
|
TModel extends (typeof GROK_CHAT_MODELS)[number],
|
|
@@ -45,7 +46,7 @@ export class GrokTextAdapter<
|
|
|
45
46
|
ResolveInputModalities<TModel>,
|
|
46
47
|
TToolCapabilities extends ReadonlyArray<string> =
|
|
47
48
|
ResolveToolCapabilities<TModel>,
|
|
48
|
-
> extends
|
|
49
|
+
> extends OpenAIBaseChatCompletionsTextAdapter<
|
|
49
50
|
TModel,
|
|
50
51
|
TProviderOptions,
|
|
51
52
|
TInputModalities,
|
|
@@ -56,7 +57,27 @@ export class GrokTextAdapter<
|
|
|
56
57
|
readonly name = 'grok' as const
|
|
57
58
|
|
|
58
59
|
constructor(config: GrokTextConfig, model: TModel) {
|
|
59
|
-
super(
|
|
60
|
+
super(model, 'grok', new OpenAI(withGrokDefaults(config)))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Surfaces xAI reasoning deltas on Grok reasoning models. The DeepSeek-style
|
|
65
|
+
* convention puts the chain-of-thought on `delta.reasoning_content`; some
|
|
66
|
+
* Grok variants also populate `delta.reasoning`. Reading both keeps
|
|
67
|
+
* reasoning flowing through the base's REASONING_* lifecycle for both
|
|
68
|
+
* `chatStream` and `structuredOutputStream`.
|
|
69
|
+
*/
|
|
70
|
+
protected override extractReasoning(
|
|
71
|
+
chunk: OpenAI.Chat.Completions.ChatCompletionChunk,
|
|
72
|
+
): { text: string } | undefined {
|
|
73
|
+
const delta = chunk.choices[0]?.delta as
|
|
74
|
+
| { reasoning?: unknown; reasoning_content?: unknown }
|
|
75
|
+
| undefined
|
|
76
|
+
const raw = delta?.reasoning_content ?? delta?.reasoning
|
|
77
|
+
if (typeof raw === 'string' && raw.length > 0) {
|
|
78
|
+
return { text: raw }
|
|
79
|
+
}
|
|
80
|
+
return undefined
|
|
60
81
|
}
|
|
61
82
|
}
|
|
62
83
|
|
package/src/index.ts
CHANGED
|
@@ -11,13 +11,11 @@ export {
|
|
|
11
11
|
type GrokTextProviderOptions,
|
|
12
12
|
} from './adapters/text'
|
|
13
13
|
|
|
14
|
-
// Summarize
|
|
14
|
+
// Summarize - thin factory functions over @tanstack/ai's ChatStreamSummarizeAdapter
|
|
15
15
|
export {
|
|
16
|
-
GrokSummarizeAdapter,
|
|
17
16
|
createGrokSummarize,
|
|
18
17
|
grokSummarize,
|
|
19
18
|
type GrokSummarizeConfig,
|
|
20
|
-
type GrokSummarizeProviderOptions,
|
|
21
19
|
type GrokSummarizeModel,
|
|
22
20
|
} from './adapters/summarize'
|
|
23
21
|
|
package/src/utils/client.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { getApiKeyFromEnv } from '@tanstack/ai-utils'
|
|
2
|
-
import type {
|
|
2
|
+
import type { ClientOptions } from 'openai'
|
|
3
3
|
|
|
4
|
-
export interface GrokClientConfig extends
|
|
4
|
+
export interface GrokClientConfig extends Omit<ClientOptions, 'apiKey'> {
|
|
5
|
+
apiKey: string
|
|
6
|
+
}
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Gets Grok API key from environment variables
|
|
@@ -21,9 +23,7 @@ export function getGrokApiKeyFromEnv(): string {
|
|
|
21
23
|
* Returns a Grok client config with the default xAI base URL applied
|
|
22
24
|
* when not already set.
|
|
23
25
|
*/
|
|
24
|
-
export function withGrokDefaults(
|
|
25
|
-
config: GrokClientConfig,
|
|
26
|
-
): OpenAICompatibleClientConfig {
|
|
26
|
+
export function withGrokDefaults(config: GrokClientConfig): GrokClientConfig {
|
|
27
27
|
return {
|
|
28
28
|
...config,
|
|
29
29
|
baseURL: config.baseURL || 'https://api.x.ai/v1',
|