@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.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +113 -28
  3. package/dist/esm/adapters/image.d.ts +77 -0
  4. package/dist/esm/adapters/image.js +63 -0
  5. package/dist/esm/adapters/image.js.map +1 -0
  6. package/dist/esm/adapters/summarize.d.ts +75 -0
  7. package/dist/esm/adapters/summarize.js +86 -0
  8. package/dist/esm/adapters/summarize.js.map +1 -0
  9. package/dist/esm/adapters/text.d.ts +96 -0
  10. package/dist/esm/adapters/text.js +371 -0
  11. package/dist/esm/adapters/text.js.map +1 -0
  12. package/dist/esm/image/image-provider-options.d.ts +66 -0
  13. package/dist/esm/image/image-provider-options.js +39 -0
  14. package/dist/esm/image/image-provider-options.js.map +1 -0
  15. package/dist/esm/index.d.ts +7 -0
  16. package/dist/esm/index.js +18 -0
  17. package/dist/esm/index.js.map +1 -0
  18. package/dist/esm/message-types.d.ts +64 -0
  19. package/dist/esm/model-meta.d.ts +223 -0
  20. package/dist/esm/model-meta.js +47 -0
  21. package/dist/esm/model-meta.js.map +1 -0
  22. package/dist/esm/text/text-provider-options.d.ts +66 -0
  23. package/dist/esm/text/text-provider-options.js +6 -0
  24. package/dist/esm/text/text-provider-options.js.map +1 -0
  25. package/dist/esm/tools/function-tool.d.ts +15 -0
  26. package/dist/esm/tools/function-tool.js +27 -0
  27. package/dist/esm/tools/function-tool.js.map +1 -0
  28. package/dist/esm/tools/index.d.ts +2 -0
  29. package/dist/esm/tools/tool-converter.d.ts +7 -0
  30. package/dist/esm/tools/tool-converter.js +10 -0
  31. package/dist/esm/tools/tool-converter.js.map +1 -0
  32. package/dist/esm/utils/client.d.ts +18 -0
  33. package/dist/esm/utils/client.js +26 -0
  34. package/dist/esm/utils/client.js.map +1 -0
  35. package/dist/esm/utils/index.d.ts +2 -0
  36. package/dist/esm/utils/schema-converter.d.ts +24 -0
  37. package/dist/esm/utils/schema-converter.js +71 -0
  38. package/dist/esm/utils/schema-converter.js.map +1 -0
  39. package/package.json +50 -7
  40. package/src/adapters/image.ts +176 -0
  41. package/src/adapters/summarize.ts +181 -0
  42. package/src/adapters/text.ts +612 -0
  43. package/src/image/image-provider-options.ts +118 -0
  44. package/src/index.ts +55 -0
  45. package/src/message-types.ts +67 -0
  46. package/src/model-meta.ts +298 -0
  47. package/src/text/text-provider-options.ts +77 -0
  48. package/src/tools/function-tool.ts +45 -0
  49. package/src/tools/index.ts +5 -0
  50. package/src/tools/tool-converter.ts +17 -0
  51. package/src/utils/client.ts +45 -0
  52. package/src/utils/index.ts +10 -0
  53. 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.1",
4
- "description": "OIDC trusted publishing setup package for @tanstack/ai-grok",
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
- "oidc",
7
- "trusted-publishing",
8
- "setup"
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
+ }