@tanstack/ai-grok 0.0.1 → 0.3.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/LICENSE +21 -0
- package/README.md +113 -28
- package/dist/esm/adapters/image.d.ts +77 -0
- package/dist/esm/adapters/image.js +63 -0
- package/dist/esm/adapters/image.js.map +1 -0
- package/dist/esm/adapters/summarize.d.ts +75 -0
- package/dist/esm/adapters/summarize.js +86 -0
- package/dist/esm/adapters/summarize.js.map +1 -0
- package/dist/esm/adapters/text.d.ts +96 -0
- package/dist/esm/adapters/text.js +371 -0
- package/dist/esm/adapters/text.js.map +1 -0
- package/dist/esm/image/image-provider-options.d.ts +66 -0
- package/dist/esm/image/image-provider-options.js +39 -0
- package/dist/esm/image/image-provider-options.js.map +1 -0
- package/dist/esm/index.d.ts +7 -0
- package/dist/esm/index.js +18 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/message-types.d.ts +64 -0
- package/dist/esm/model-meta.d.ts +223 -0
- package/dist/esm/model-meta.js +47 -0
- package/dist/esm/model-meta.js.map +1 -0
- package/dist/esm/text/text-provider-options.d.ts +66 -0
- package/dist/esm/text/text-provider-options.js +6 -0
- package/dist/esm/text/text-provider-options.js.map +1 -0
- package/dist/esm/tools/function-tool.d.ts +15 -0
- package/dist/esm/tools/function-tool.js +27 -0
- package/dist/esm/tools/function-tool.js.map +1 -0
- package/dist/esm/tools/index.d.ts +2 -0
- package/dist/esm/tools/tool-converter.d.ts +7 -0
- package/dist/esm/tools/tool-converter.js +10 -0
- package/dist/esm/tools/tool-converter.js.map +1 -0
- package/dist/esm/utils/client.d.ts +18 -0
- package/dist/esm/utils/client.js +26 -0
- package/dist/esm/utils/client.js.map +1 -0
- package/dist/esm/utils/index.d.ts +2 -0
- package/dist/esm/utils/schema-converter.d.ts +24 -0
- package/dist/esm/utils/schema-converter.js +71 -0
- package/dist/esm/utils/schema-converter.js.map +1 -0
- package/package.json +50 -7
- package/src/adapters/image.ts +176 -0
- package/src/adapters/summarize.ts +181 -0
- package/src/adapters/text.ts +612 -0
- package/src/image/image-provider-options.ts +118 -0
- package/src/index.ts +55 -0
- package/src/message-types.ts +67 -0
- package/src/model-meta.ts +298 -0
- package/src/text/text-provider-options.ts +77 -0
- package/src/tools/function-tool.ts +45 -0
- package/src/tools/index.ts +5 -0
- package/src/tools/tool-converter.ts +17 -0
- package/src/utils/client.ts +45 -0
- package/src/utils/index.ts +10 -0
- package/src/utils/schema-converter.ts +110 -0
package/package.json
CHANGED
|
@@ -1,10 +1,53 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/ai-grok",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Grok (xAI) adapter for TanStack AI",
|
|
5
|
+
"author": "",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/TanStack/ai.git",
|
|
10
|
+
"directory": "packages/typescript/ai-grok"
|
|
11
|
+
},
|
|
12
|
+
"type": "module",
|
|
13
|
+
"module": "./dist/esm/index.js",
|
|
14
|
+
"types": "./dist/esm/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/esm/index.d.ts",
|
|
18
|
+
"import": "./dist/esm/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"src"
|
|
24
|
+
],
|
|
5
25
|
"keywords": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
26
|
+
"ai",
|
|
27
|
+
"grok",
|
|
28
|
+
"xai",
|
|
29
|
+
"tanstack",
|
|
30
|
+
"adapter"
|
|
31
|
+
],
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"openai": "^6.9.1"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@vitest/coverage-v8": "4.0.14",
|
|
37
|
+
"vite": "^7.2.7"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"zod": "^4.0.0",
|
|
41
|
+
"@tanstack/ai": "^0.3.0"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "vite build",
|
|
45
|
+
"clean": "premove ./build ./dist",
|
|
46
|
+
"lint:fix": "eslint ./src --fix",
|
|
47
|
+
"test:build": "publint --strict",
|
|
48
|
+
"test:eslint": "eslint ./src",
|
|
49
|
+
"test:lib": "vitest run",
|
|
50
|
+
"test:lib:dev": "pnpm test:lib --watch",
|
|
51
|
+
"test:types": "tsc"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { BaseImageAdapter } from '@tanstack/ai/adapters'
|
|
2
|
+
import { createGrokClient, generateId, getGrokApiKeyFromEnv } from '../utils'
|
|
3
|
+
import {
|
|
4
|
+
validateImageSize,
|
|
5
|
+
validateNumberOfImages,
|
|
6
|
+
validatePrompt,
|
|
7
|
+
} from '../image/image-provider-options'
|
|
8
|
+
import type { GROK_IMAGE_MODELS } from '../model-meta'
|
|
9
|
+
import type {
|
|
10
|
+
GrokImageModelProviderOptionsByName,
|
|
11
|
+
GrokImageModelSizeByName,
|
|
12
|
+
GrokImageProviderOptions,
|
|
13
|
+
} from '../image/image-provider-options'
|
|
14
|
+
import type {
|
|
15
|
+
GeneratedImage,
|
|
16
|
+
ImageGenerationOptions,
|
|
17
|
+
ImageGenerationResult,
|
|
18
|
+
} from '@tanstack/ai'
|
|
19
|
+
import type OpenAI_SDK from 'openai'
|
|
20
|
+
import type { GrokClientConfig } from '../utils'
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Configuration for Grok image adapter
|
|
24
|
+
*/
|
|
25
|
+
export interface GrokImageConfig extends GrokClientConfig {}
|
|
26
|
+
|
|
27
|
+
/** Model type for Grok Image */
|
|
28
|
+
export type GrokImageModel = (typeof GROK_IMAGE_MODELS)[number]
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Grok Image Generation Adapter
|
|
32
|
+
*
|
|
33
|
+
* Tree-shakeable adapter for Grok image generation functionality.
|
|
34
|
+
* Supports grok-2-image-1212 model.
|
|
35
|
+
*
|
|
36
|
+
* Features:
|
|
37
|
+
* - Model-specific type-safe provider options
|
|
38
|
+
* - Size validation per model
|
|
39
|
+
* - Number of images validation
|
|
40
|
+
*/
|
|
41
|
+
export class GrokImageAdapter<
|
|
42
|
+
TModel extends GrokImageModel,
|
|
43
|
+
> extends BaseImageAdapter<
|
|
44
|
+
TModel,
|
|
45
|
+
GrokImageProviderOptions,
|
|
46
|
+
GrokImageModelProviderOptionsByName,
|
|
47
|
+
GrokImageModelSizeByName
|
|
48
|
+
> {
|
|
49
|
+
readonly kind = 'image' as const
|
|
50
|
+
readonly name = 'grok' as const
|
|
51
|
+
|
|
52
|
+
private client: OpenAI_SDK
|
|
53
|
+
|
|
54
|
+
constructor(config: GrokImageConfig, model: TModel) {
|
|
55
|
+
super({}, model)
|
|
56
|
+
this.client = createGrokClient(config)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async generateImages(
|
|
60
|
+
options: ImageGenerationOptions<GrokImageProviderOptions>,
|
|
61
|
+
): Promise<ImageGenerationResult> {
|
|
62
|
+
const { model, prompt, numberOfImages, size } = options
|
|
63
|
+
|
|
64
|
+
// Validate inputs
|
|
65
|
+
validatePrompt({ prompt, model })
|
|
66
|
+
validateImageSize(model, size)
|
|
67
|
+
validateNumberOfImages(model, numberOfImages)
|
|
68
|
+
|
|
69
|
+
// Build request based on model type
|
|
70
|
+
const request = this.buildRequest(options)
|
|
71
|
+
|
|
72
|
+
const response = await this.client.images.generate({
|
|
73
|
+
...request,
|
|
74
|
+
stream: false,
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
return this.transformResponse(model, response)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private buildRequest(
|
|
81
|
+
options: ImageGenerationOptions<GrokImageProviderOptions>,
|
|
82
|
+
): OpenAI_SDK.Images.ImageGenerateParams {
|
|
83
|
+
const { model, prompt, numberOfImages, size, modelOptions } = options
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
model,
|
|
87
|
+
prompt,
|
|
88
|
+
n: numberOfImages ?? 1,
|
|
89
|
+
size: size as OpenAI_SDK.Images.ImageGenerateParams['size'],
|
|
90
|
+
...modelOptions,
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private transformResponse(
|
|
95
|
+
model: string,
|
|
96
|
+
response: OpenAI_SDK.Images.ImagesResponse,
|
|
97
|
+
): ImageGenerationResult {
|
|
98
|
+
const images: Array<GeneratedImage> = (response.data ?? []).map((item) => ({
|
|
99
|
+
b64Json: item.b64_json,
|
|
100
|
+
url: item.url,
|
|
101
|
+
revisedPrompt: item.revised_prompt,
|
|
102
|
+
}))
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
id: generateId(this.name),
|
|
106
|
+
model,
|
|
107
|
+
images,
|
|
108
|
+
usage: response.usage
|
|
109
|
+
? {
|
|
110
|
+
inputTokens: response.usage.input_tokens,
|
|
111
|
+
outputTokens: response.usage.output_tokens,
|
|
112
|
+
totalTokens: response.usage.total_tokens,
|
|
113
|
+
}
|
|
114
|
+
: undefined,
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Creates a Grok image adapter with explicit API key.
|
|
121
|
+
* Type resolution happens here at the call site.
|
|
122
|
+
*
|
|
123
|
+
* @param model - The model name (e.g., 'grok-2-image-1212')
|
|
124
|
+
* @param apiKey - Your xAI API key
|
|
125
|
+
* @param config - Optional additional configuration
|
|
126
|
+
* @returns Configured Grok image adapter instance with resolved types
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* const adapter = createGrokImage('grok-2-image-1212', "xai-...");
|
|
131
|
+
*
|
|
132
|
+
* const result = await generateImage({
|
|
133
|
+
* adapter,
|
|
134
|
+
* prompt: 'A cute baby sea otter'
|
|
135
|
+
* });
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
export function createGrokImage<TModel extends GrokImageModel>(
|
|
139
|
+
model: TModel,
|
|
140
|
+
apiKey: string,
|
|
141
|
+
config?: Omit<GrokImageConfig, 'apiKey'>,
|
|
142
|
+
): GrokImageAdapter<TModel> {
|
|
143
|
+
return new GrokImageAdapter({ apiKey, ...config }, model)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Creates a Grok image adapter with automatic API key detection from environment variables.
|
|
148
|
+
* Type resolution happens here at the call site.
|
|
149
|
+
*
|
|
150
|
+
* Looks for `XAI_API_KEY` in:
|
|
151
|
+
* - `process.env` (Node.js)
|
|
152
|
+
* - `window.env` (Browser with injected env)
|
|
153
|
+
*
|
|
154
|
+
* @param model - The model name (e.g., 'grok-2-image-1212')
|
|
155
|
+
* @param config - Optional configuration (excluding apiKey which is auto-detected)
|
|
156
|
+
* @returns Configured Grok image adapter instance with resolved types
|
|
157
|
+
* @throws Error if XAI_API_KEY is not found in environment
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* // Automatically uses XAI_API_KEY from environment
|
|
162
|
+
* const adapter = grokImage('grok-2-image-1212');
|
|
163
|
+
*
|
|
164
|
+
* const result = await generateImage({
|
|
165
|
+
* adapter,
|
|
166
|
+
* prompt: 'A beautiful sunset over mountains'
|
|
167
|
+
* });
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
export function grokImage<TModel extends GrokImageModel>(
|
|
171
|
+
model: TModel,
|
|
172
|
+
config?: Omit<GrokImageConfig, 'apiKey'>,
|
|
173
|
+
): GrokImageAdapter<TModel> {
|
|
174
|
+
const apiKey = getGrokApiKeyFromEnv()
|
|
175
|
+
return createGrokImage(model, apiKey, config)
|
|
176
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { BaseSummarizeAdapter } from '@tanstack/ai/adapters'
|
|
2
|
+
import { getGrokApiKeyFromEnv } from '../utils'
|
|
3
|
+
import { GrokTextAdapter } from './text'
|
|
4
|
+
import type { GROK_CHAT_MODELS } from '../model-meta'
|
|
5
|
+
import type {
|
|
6
|
+
StreamChunk,
|
|
7
|
+
SummarizationOptions,
|
|
8
|
+
SummarizationResult,
|
|
9
|
+
} from '@tanstack/ai'
|
|
10
|
+
import type { GrokClientConfig } from '../utils'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Configuration for Grok summarize adapter
|
|
14
|
+
*/
|
|
15
|
+
export interface GrokSummarizeConfig extends GrokClientConfig {}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Grok-specific provider options for summarization
|
|
19
|
+
*/
|
|
20
|
+
export interface GrokSummarizeProviderOptions {
|
|
21
|
+
/** Temperature for response generation (0-2) */
|
|
22
|
+
temperature?: number
|
|
23
|
+
/** Maximum tokens in the response */
|
|
24
|
+
maxTokens?: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Model type for Grok summarization */
|
|
28
|
+
export type GrokSummarizeModel = (typeof GROK_CHAT_MODELS)[number]
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Grok Summarize Adapter
|
|
32
|
+
*
|
|
33
|
+
* A thin wrapper around the text adapter that adds summarization-specific prompting.
|
|
34
|
+
* Delegates all API calls to the GrokTextAdapter.
|
|
35
|
+
*/
|
|
36
|
+
export class GrokSummarizeAdapter<
|
|
37
|
+
TModel extends GrokSummarizeModel,
|
|
38
|
+
> extends BaseSummarizeAdapter<TModel, GrokSummarizeProviderOptions> {
|
|
39
|
+
readonly kind = 'summarize' as const
|
|
40
|
+
readonly name = 'grok' as const
|
|
41
|
+
|
|
42
|
+
private textAdapter: GrokTextAdapter<TModel>
|
|
43
|
+
|
|
44
|
+
constructor(config: GrokSummarizeConfig, model: TModel) {
|
|
45
|
+
super({}, model)
|
|
46
|
+
this.textAdapter = new GrokTextAdapter(config, model)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async summarize(options: SummarizationOptions): Promise<SummarizationResult> {
|
|
50
|
+
const systemPrompt = this.buildSummarizationPrompt(options)
|
|
51
|
+
|
|
52
|
+
// Use the text adapter's streaming and collect the result
|
|
53
|
+
let summary = ''
|
|
54
|
+
const id = ''
|
|
55
|
+
let model = options.model
|
|
56
|
+
let usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 }
|
|
57
|
+
|
|
58
|
+
for await (const chunk of this.textAdapter.chatStream({
|
|
59
|
+
model: options.model,
|
|
60
|
+
messages: [{ role: 'user', content: options.text }],
|
|
61
|
+
systemPrompts: [systemPrompt],
|
|
62
|
+
maxTokens: options.maxLength,
|
|
63
|
+
temperature: 0.3,
|
|
64
|
+
})) {
|
|
65
|
+
// AG-UI TEXT_MESSAGE_CONTENT event
|
|
66
|
+
if (chunk.type === 'TEXT_MESSAGE_CONTENT') {
|
|
67
|
+
if (chunk.content) {
|
|
68
|
+
summary = chunk.content
|
|
69
|
+
} else {
|
|
70
|
+
summary += chunk.delta
|
|
71
|
+
}
|
|
72
|
+
model = chunk.model || model
|
|
73
|
+
}
|
|
74
|
+
// AG-UI RUN_FINISHED event
|
|
75
|
+
if (chunk.type === 'RUN_FINISHED') {
|
|
76
|
+
if (chunk.usage) {
|
|
77
|
+
usage = chunk.usage
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return { id, model, summary, usage }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async *summarizeStream(
|
|
86
|
+
options: SummarizationOptions,
|
|
87
|
+
): AsyncIterable<StreamChunk> {
|
|
88
|
+
const systemPrompt = this.buildSummarizationPrompt(options)
|
|
89
|
+
|
|
90
|
+
// Delegate directly to the text adapter's streaming
|
|
91
|
+
yield* this.textAdapter.chatStream({
|
|
92
|
+
model: options.model,
|
|
93
|
+
messages: [{ role: 'user', content: options.text }],
|
|
94
|
+
systemPrompts: [systemPrompt],
|
|
95
|
+
maxTokens: options.maxLength,
|
|
96
|
+
temperature: 0.3,
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private buildSummarizationPrompt(options: SummarizationOptions): string {
|
|
101
|
+
let prompt = 'You are a professional summarizer. '
|
|
102
|
+
|
|
103
|
+
switch (options.style) {
|
|
104
|
+
case 'bullet-points':
|
|
105
|
+
prompt += 'Provide a summary in bullet point format. '
|
|
106
|
+
break
|
|
107
|
+
case 'paragraph':
|
|
108
|
+
prompt += 'Provide a summary in paragraph format. '
|
|
109
|
+
break
|
|
110
|
+
case 'concise':
|
|
111
|
+
prompt += 'Provide a very concise summary in 1-2 sentences. '
|
|
112
|
+
break
|
|
113
|
+
default:
|
|
114
|
+
prompt += 'Provide a clear and concise summary. '
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (options.focus && options.focus.length > 0) {
|
|
118
|
+
prompt += `Focus on the following aspects: ${options.focus.join(', ')}. `
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (options.maxLength) {
|
|
122
|
+
prompt += `Keep the summary under ${options.maxLength} tokens. `
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return prompt
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Creates a Grok summarize adapter with explicit API key.
|
|
131
|
+
* Type resolution happens here at the call site.
|
|
132
|
+
*
|
|
133
|
+
* @param model - The model name (e.g., 'grok-3', 'grok-4')
|
|
134
|
+
* @param apiKey - Your xAI API key
|
|
135
|
+
* @param config - Optional additional configuration
|
|
136
|
+
* @returns Configured Grok summarize adapter instance with resolved types
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* const adapter = createGrokSummarize('grok-3', "xai-...");
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
export function createGrokSummarize<TModel extends GrokSummarizeModel>(
|
|
144
|
+
model: TModel,
|
|
145
|
+
apiKey: string,
|
|
146
|
+
config?: Omit<GrokSummarizeConfig, 'apiKey'>,
|
|
147
|
+
): GrokSummarizeAdapter<TModel> {
|
|
148
|
+
return new GrokSummarizeAdapter({ apiKey, ...config }, model)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Creates a Grok summarize adapter with automatic API key detection from environment variables.
|
|
153
|
+
* Type resolution happens here at the call site.
|
|
154
|
+
*
|
|
155
|
+
* Looks for `XAI_API_KEY` in:
|
|
156
|
+
* - `process.env` (Node.js)
|
|
157
|
+
* - `window.env` (Browser with injected env)
|
|
158
|
+
*
|
|
159
|
+
* @param model - The model name (e.g., 'grok-3', 'grok-4')
|
|
160
|
+
* @param config - Optional configuration (excluding apiKey which is auto-detected)
|
|
161
|
+
* @returns Configured Grok summarize adapter instance with resolved types
|
|
162
|
+
* @throws Error if XAI_API_KEY is not found in environment
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* // Automatically uses XAI_API_KEY from environment
|
|
167
|
+
* const adapter = grokSummarize('grok-3');
|
|
168
|
+
*
|
|
169
|
+
* await summarize({
|
|
170
|
+
* adapter,
|
|
171
|
+
* text: "Long article text..."
|
|
172
|
+
* });
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
export function grokSummarize<TModel extends GrokSummarizeModel>(
|
|
176
|
+
model: TModel,
|
|
177
|
+
config?: Omit<GrokSummarizeConfig, 'apiKey'>,
|
|
178
|
+
): GrokSummarizeAdapter<TModel> {
|
|
179
|
+
const apiKey = getGrokApiKeyFromEnv()
|
|
180
|
+
return createGrokSummarize(model, apiKey, config)
|
|
181
|
+
}
|