@tanstack/ai-grok 0.0.1 → 0.1.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 +81 -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 +300 -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 +174 -0
  42. package/src/adapters/text.ts +506 -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.1.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.2.1"
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,174 @@
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
+ let 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
+ if (chunk.type === 'content') {
66
+ summary = chunk.content
67
+ id = chunk.id
68
+ model = chunk.model
69
+ }
70
+ if (chunk.type === 'done' && chunk.usage) {
71
+ usage = chunk.usage
72
+ }
73
+ }
74
+
75
+ return { id, model, summary, usage }
76
+ }
77
+
78
+ async *summarizeStream(
79
+ options: SummarizationOptions,
80
+ ): AsyncIterable<StreamChunk> {
81
+ const systemPrompt = this.buildSummarizationPrompt(options)
82
+
83
+ // Delegate directly to the text adapter's streaming
84
+ yield* this.textAdapter.chatStream({
85
+ model: options.model,
86
+ messages: [{ role: 'user', content: options.text }],
87
+ systemPrompts: [systemPrompt],
88
+ maxTokens: options.maxLength,
89
+ temperature: 0.3,
90
+ })
91
+ }
92
+
93
+ private buildSummarizationPrompt(options: SummarizationOptions): string {
94
+ let prompt = 'You are a professional summarizer. '
95
+
96
+ switch (options.style) {
97
+ case 'bullet-points':
98
+ prompt += 'Provide a summary in bullet point format. '
99
+ break
100
+ case 'paragraph':
101
+ prompt += 'Provide a summary in paragraph format. '
102
+ break
103
+ case 'concise':
104
+ prompt += 'Provide a very concise summary in 1-2 sentences. '
105
+ break
106
+ default:
107
+ prompt += 'Provide a clear and concise summary. '
108
+ }
109
+
110
+ if (options.focus && options.focus.length > 0) {
111
+ prompt += `Focus on the following aspects: ${options.focus.join(', ')}. `
112
+ }
113
+
114
+ if (options.maxLength) {
115
+ prompt += `Keep the summary under ${options.maxLength} tokens. `
116
+ }
117
+
118
+ return prompt
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Creates a Grok summarize adapter with explicit API key.
124
+ * Type resolution happens here at the call site.
125
+ *
126
+ * @param model - The model name (e.g., 'grok-3', 'grok-4')
127
+ * @param apiKey - Your xAI API key
128
+ * @param config - Optional additional configuration
129
+ * @returns Configured Grok summarize adapter instance with resolved types
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * const adapter = createGrokSummarize('grok-3', "xai-...");
134
+ * ```
135
+ */
136
+ export function createGrokSummarize<TModel extends GrokSummarizeModel>(
137
+ model: TModel,
138
+ apiKey: string,
139
+ config?: Omit<GrokSummarizeConfig, 'apiKey'>,
140
+ ): GrokSummarizeAdapter<TModel> {
141
+ return new GrokSummarizeAdapter({ apiKey, ...config }, model)
142
+ }
143
+
144
+ /**
145
+ * Creates a Grok summarize adapter with automatic API key detection from environment variables.
146
+ * Type resolution happens here at the call site.
147
+ *
148
+ * Looks for `XAI_API_KEY` in:
149
+ * - `process.env` (Node.js)
150
+ * - `window.env` (Browser with injected env)
151
+ *
152
+ * @param model - The model name (e.g., 'grok-3', 'grok-4')
153
+ * @param config - Optional configuration (excluding apiKey which is auto-detected)
154
+ * @returns Configured Grok summarize adapter instance with resolved types
155
+ * @throws Error if XAI_API_KEY is not found in environment
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * // Automatically uses XAI_API_KEY from environment
160
+ * const adapter = grokSummarize('grok-3');
161
+ *
162
+ * await summarize({
163
+ * adapter,
164
+ * text: "Long article text..."
165
+ * });
166
+ * ```
167
+ */
168
+ export function grokSummarize<TModel extends GrokSummarizeModel>(
169
+ model: TModel,
170
+ config?: Omit<GrokSummarizeConfig, 'apiKey'>,
171
+ ): GrokSummarizeAdapter<TModel> {
172
+ const apiKey = getGrokApiKeyFromEnv()
173
+ return createGrokSummarize(model, apiKey, config)
174
+ }