@tanstack/ai-groq 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 (40) hide show
  1. package/README.md +91 -0
  2. package/dist/esm/adapters/text.d.ts +104 -0
  3. package/dist/esm/adapters/text.js +384 -0
  4. package/dist/esm/adapters/text.js.map +1 -0
  5. package/dist/esm/index.d.ts +10 -0
  6. package/dist/esm/index.js +9 -0
  7. package/dist/esm/index.js.map +1 -0
  8. package/dist/esm/message-types.d.ts +292 -0
  9. package/dist/esm/model-meta.d.ts +275 -0
  10. package/dist/esm/model-meta.js +54 -0
  11. package/dist/esm/model-meta.js.map +1 -0
  12. package/dist/esm/text/text-provider-options.d.ts +179 -0
  13. package/dist/esm/text/text-provider-options.js +6 -0
  14. package/dist/esm/text/text-provider-options.js.map +1 -0
  15. package/dist/esm/tools/function-tool.d.ts +13 -0
  16. package/dist/esm/tools/function-tool.js +29 -0
  17. package/dist/esm/tools/function-tool.js.map +1 -0
  18. package/dist/esm/tools/index.d.ts +2 -0
  19. package/dist/esm/tools/tool-converter.d.ts +7 -0
  20. package/dist/esm/tools/tool-converter.js +10 -0
  21. package/dist/esm/tools/tool-converter.js.map +1 -0
  22. package/dist/esm/utils/client.d.ts +17 -0
  23. package/dist/esm/utils/client.js +23 -0
  24. package/dist/esm/utils/client.js.map +1 -0
  25. package/dist/esm/utils/index.d.ts +2 -0
  26. package/dist/esm/utils/schema-converter.d.ts +25 -0
  27. package/dist/esm/utils/schema-converter.js +78 -0
  28. package/dist/esm/utils/schema-converter.js.map +1 -0
  29. package/package.json +52 -0
  30. package/src/adapters/text.ts +599 -0
  31. package/src/index.ts +33 -0
  32. package/src/message-types.ts +359 -0
  33. package/src/model-meta.ts +370 -0
  34. package/src/text/text-provider-options.ts +225 -0
  35. package/src/tools/function-tool.ts +44 -0
  36. package/src/tools/index.ts +5 -0
  37. package/src/tools/tool-converter.ts +15 -0
  38. package/src/utils/client.ts +42 -0
  39. package/src/utils/index.ts +10 -0
  40. package/src/utils/schema-converter.ts +110 -0
@@ -0,0 +1,370 @@
1
+ import type { GroqTextProviderOptions } from './text/text-provider-options'
2
+
3
+ /**
4
+ * Internal metadata structure describing a Groq model's capabilities and pricing.
5
+ */
6
+ interface ModelMeta<TProviderOptions = unknown> {
7
+ name: string
8
+ context_window?: number
9
+ max_completion_tokens?: number
10
+ pricing: {
11
+ input?: { normal: number; cached?: number }
12
+ output?: { normal: number }
13
+ }
14
+ supports: {
15
+ input: Array<'text' | 'image' | 'audio'>
16
+ output: Array<'text' | 'audio'>
17
+ endpoints: Array<'chat' | 'tts' | 'transcription' | 'batch'>
18
+
19
+ features: Array<
20
+ | 'streaming'
21
+ | 'tools'
22
+ | 'json_object'
23
+ | 'browser_search'
24
+ | 'code_execution'
25
+ | 'reasoning'
26
+ | 'content_moderation'
27
+ | 'json_schema'
28
+ | 'vision'
29
+ >
30
+ }
31
+ /**
32
+ * Type-level description of which provider options this model supports.
33
+ */
34
+ providerOptions?: TProviderOptions
35
+ }
36
+
37
+ const LLAMA_3_3_70B_VERSATILE = {
38
+ name: 'llama-3.3-70b-versatile',
39
+ context_window: 131_072,
40
+ max_completion_tokens: 32_768,
41
+ pricing: {
42
+ input: {
43
+ normal: 0.59,
44
+ },
45
+ output: {
46
+ normal: 0.79,
47
+ },
48
+ },
49
+ supports: {
50
+ input: ['text'],
51
+ output: ['text'],
52
+ endpoints: ['chat'],
53
+ features: ['streaming', 'tools', 'json_object'],
54
+ },
55
+ } as const satisfies ModelMeta<GroqTextProviderOptions>
56
+
57
+ const LLAMA_4_MAVERICK_17B_128E_INSTRUCT = {
58
+ name: 'meta-llama/llama-4-maverick-17b-128e-instruct',
59
+ context_window: 131_072,
60
+ max_completion_tokens: 8_192,
61
+ pricing: {
62
+ input: {
63
+ normal: 0.2,
64
+ },
65
+ output: {
66
+ normal: 0.6,
67
+ },
68
+ },
69
+ supports: {
70
+ input: ['text', 'image'],
71
+ output: ['text'],
72
+ endpoints: ['chat'],
73
+ features: ['streaming', 'tools', 'json_object', 'json_schema', 'vision'],
74
+ },
75
+ } as const satisfies ModelMeta<GroqTextProviderOptions>
76
+
77
+ const LLAMA_4_SCOUT_17B_16E_INSTRUCT = {
78
+ name: 'meta-llama/llama-4-scout-17b-16e-instruct',
79
+ context_window: 131_072,
80
+ max_completion_tokens: 8_192,
81
+ pricing: {
82
+ input: {
83
+ normal: 0.05,
84
+ },
85
+ output: {
86
+ normal: 0.08,
87
+ },
88
+ },
89
+ supports: {
90
+ input: ['text', 'image'],
91
+ output: ['text'],
92
+ endpoints: ['chat'],
93
+ features: ['streaming', 'tools', 'json_object'],
94
+ },
95
+ } as const satisfies ModelMeta<GroqTextProviderOptions>
96
+
97
+ const LLAMA_GUARD_4_12B = {
98
+ name: 'meta-llama/llama-guard-4-12b',
99
+ context_window: 131_072,
100
+ max_completion_tokens: 1024,
101
+ pricing: {
102
+ input: {
103
+ normal: 0.2,
104
+ },
105
+ output: {
106
+ normal: 0.2,
107
+ },
108
+ },
109
+ supports: {
110
+ input: ['text', 'image'],
111
+ output: ['text'],
112
+ endpoints: ['chat'],
113
+ features: ['streaming', 'json_object', 'content_moderation', 'vision'],
114
+ },
115
+ } as const satisfies ModelMeta<GroqTextProviderOptions>
116
+
117
+ const LLAMA_PROMPT_GUARD_2_86M = {
118
+ name: 'meta-llama/llama-prompt-guard-2-86m',
119
+ context_window: 512,
120
+ max_completion_tokens: 512,
121
+ pricing: {
122
+ input: {
123
+ normal: 0.04,
124
+ },
125
+ output: {
126
+ normal: 0.04,
127
+ },
128
+ },
129
+ supports: {
130
+ input: ['text'],
131
+ output: ['text'],
132
+ endpoints: ['chat'],
133
+ features: ['streaming', 'content_moderation', 'json_object'],
134
+ },
135
+ } as const satisfies ModelMeta<GroqTextProviderOptions>
136
+
137
+ const LLAMA_3_1_8B_INSTANT = {
138
+ name: 'llama-3.1-8b-instant',
139
+ context_window: 131_072,
140
+ max_completion_tokens: 131_072,
141
+ pricing: {
142
+ input: {
143
+ normal: 0.05,
144
+ },
145
+ output: {
146
+ normal: 0.08,
147
+ },
148
+ },
149
+ supports: {
150
+ input: ['text'],
151
+ output: ['text'],
152
+ endpoints: ['chat'],
153
+ features: ['streaming', 'json_object', 'tools'],
154
+ },
155
+ } as const satisfies ModelMeta<GroqTextProviderOptions>
156
+
157
+ const LLAMA_PROMPT_GUARD_2_22M = {
158
+ name: 'meta-llama/llama-prompt-guard-2-22m',
159
+ context_window: 512,
160
+ max_completion_tokens: 512,
161
+ pricing: {
162
+ input: {
163
+ normal: 0.03,
164
+ },
165
+ output: {
166
+ normal: 0.03,
167
+ },
168
+ },
169
+ supports: {
170
+ input: ['text'],
171
+ output: ['text'],
172
+ endpoints: ['chat'],
173
+ features: ['streaming', 'content_moderation'],
174
+ },
175
+ } as const satisfies ModelMeta<GroqTextProviderOptions>
176
+
177
+ const GPT_OSS_120B = {
178
+ name: 'openai/gpt-oss-120b',
179
+ context_window: 131_072,
180
+ max_completion_tokens: 65_536,
181
+ pricing: {
182
+ input: {
183
+ normal: 0.15,
184
+ cached: 0.075,
185
+ },
186
+ output: {
187
+ normal: 0.6,
188
+ },
189
+ },
190
+ supports: {
191
+ input: ['text'],
192
+ output: ['text'],
193
+ endpoints: ['chat'],
194
+ features: [
195
+ 'streaming',
196
+ 'json_object',
197
+ 'json_schema',
198
+ 'tools',
199
+ 'browser_search',
200
+ 'code_execution',
201
+ 'reasoning',
202
+ ],
203
+ },
204
+ } as const satisfies ModelMeta<GroqTextProviderOptions>
205
+
206
+ const GPT_OSS_SAFEGUARD_20B = {
207
+ name: 'openai/gpt-oss-safeguard-20b',
208
+ context_window: 131_072,
209
+ max_completion_tokens: 65_536,
210
+ pricing: {
211
+ input: {
212
+ normal: 0.075,
213
+ cached: 0.037,
214
+ },
215
+ output: {
216
+ normal: 0.3,
217
+ },
218
+ },
219
+ supports: {
220
+ input: ['text'],
221
+ output: ['text'],
222
+ endpoints: ['chat'],
223
+ features: [
224
+ 'streaming',
225
+ 'tools',
226
+ 'browser_search',
227
+ 'code_execution',
228
+ 'json_object',
229
+ 'json_schema',
230
+ 'reasoning',
231
+ 'content_moderation',
232
+ ],
233
+ },
234
+ } as const satisfies ModelMeta<GroqTextProviderOptions>
235
+
236
+ const GPT_OSS_20B = {
237
+ name: 'openai/gpt-oss-20b',
238
+ context_window: 131_072,
239
+ max_completion_tokens: 65_536,
240
+ pricing: {
241
+ input: {
242
+ normal: 0.075,
243
+ cached: 0.037,
244
+ },
245
+ output: {
246
+ normal: 0.3,
247
+ },
248
+ },
249
+ supports: {
250
+ input: ['text'],
251
+ output: ['text'],
252
+ endpoints: ['chat'],
253
+ features: [
254
+ 'streaming',
255
+ 'browser_search',
256
+ 'code_execution',
257
+ 'json_object',
258
+ 'json_schema',
259
+ 'reasoning',
260
+ 'tools',
261
+ ],
262
+ },
263
+ } as const satisfies ModelMeta<GroqTextProviderOptions>
264
+
265
+ const KIMI_K2_INSTRUCT_0905 = {
266
+ name: 'moonshotai/kimi-k2-instruct-0905',
267
+ context_window: 262_144,
268
+ max_completion_tokens: 16_384,
269
+ pricing: {
270
+ input: {
271
+ normal: 1,
272
+ cached: 0.5,
273
+ },
274
+ output: {
275
+ normal: 3,
276
+ },
277
+ },
278
+ supports: {
279
+ input: ['text'],
280
+ output: ['text'],
281
+ endpoints: ['chat'],
282
+ features: ['streaming', 'tools', 'json_object', 'json_schema'],
283
+ },
284
+ } as const satisfies ModelMeta<GroqTextProviderOptions>
285
+
286
+ const QWEN3_32B = {
287
+ name: 'qwen/qwen3-32b',
288
+ context_window: 131_072,
289
+ max_completion_tokens: 40_960,
290
+ pricing: {
291
+ input: {
292
+ normal: 0.29,
293
+ },
294
+ output: {
295
+ normal: 0.59,
296
+ },
297
+ },
298
+ supports: {
299
+ input: ['text'],
300
+ output: ['text'],
301
+ endpoints: ['chat'],
302
+ features: ['streaming', 'json_object', 'tools', 'reasoning'],
303
+ },
304
+ } as const satisfies ModelMeta<GroqTextProviderOptions>
305
+
306
+ /**
307
+ * All supported Groq chat model identifiers.
308
+ */
309
+ export const GROQ_CHAT_MODELS = [
310
+ LLAMA_3_1_8B_INSTANT.name,
311
+ LLAMA_3_3_70B_VERSATILE.name,
312
+ LLAMA_4_MAVERICK_17B_128E_INSTRUCT.name,
313
+ LLAMA_4_SCOUT_17B_16E_INSTRUCT.name,
314
+ LLAMA_GUARD_4_12B.name,
315
+ LLAMA_PROMPT_GUARD_2_86M.name,
316
+ LLAMA_PROMPT_GUARD_2_22M.name,
317
+ GPT_OSS_20B.name,
318
+ GPT_OSS_120B.name,
319
+ GPT_OSS_SAFEGUARD_20B.name,
320
+ KIMI_K2_INSTRUCT_0905.name,
321
+ QWEN3_32B.name,
322
+ ] as const
323
+
324
+ /**
325
+ * Union type of all supported Groq chat model names.
326
+ */
327
+ export type GroqChatModels = (typeof GROQ_CHAT_MODELS)[number]
328
+
329
+ /**
330
+ * Type-only map from Groq chat model name to its supported input modalities.
331
+ */
332
+ export type GroqModelInputModalitiesByName = {
333
+ [LLAMA_3_1_8B_INSTANT.name]: typeof LLAMA_3_1_8B_INSTANT.supports.input
334
+ [LLAMA_3_3_70B_VERSATILE.name]: typeof LLAMA_3_3_70B_VERSATILE.supports.input
335
+ [LLAMA_4_MAVERICK_17B_128E_INSTRUCT.name]: typeof LLAMA_4_MAVERICK_17B_128E_INSTRUCT.supports.input
336
+ [LLAMA_4_SCOUT_17B_16E_INSTRUCT.name]: typeof LLAMA_4_SCOUT_17B_16E_INSTRUCT.supports.input
337
+ [LLAMA_GUARD_4_12B.name]: typeof LLAMA_GUARD_4_12B.supports.input
338
+ [LLAMA_PROMPT_GUARD_2_86M.name]: typeof LLAMA_PROMPT_GUARD_2_86M.supports.input
339
+ [LLAMA_PROMPT_GUARD_2_22M.name]: typeof LLAMA_PROMPT_GUARD_2_22M.supports.input
340
+ [GPT_OSS_20B.name]: typeof GPT_OSS_20B.supports.input
341
+ [GPT_OSS_120B.name]: typeof GPT_OSS_120B.supports.input
342
+ [GPT_OSS_SAFEGUARD_20B.name]: typeof GPT_OSS_SAFEGUARD_20B.supports.input
343
+ [KIMI_K2_INSTRUCT_0905.name]: typeof KIMI_K2_INSTRUCT_0905.supports.input
344
+ [QWEN3_32B.name]: typeof QWEN3_32B.supports.input
345
+ }
346
+
347
+ /**
348
+ * Type-only map from Groq chat model name to its provider options type.
349
+ */
350
+ export type GroqChatModelProviderOptionsByName = {
351
+ [K in (typeof GROQ_CHAT_MODELS)[number]]: GroqTextProviderOptions
352
+ }
353
+
354
+ /**
355
+ * Resolves the provider options type for a specific Groq model.
356
+ * Falls back to generic GroqTextProviderOptions for unknown models.
357
+ */
358
+ export type ResolveProviderOptions<TModel extends string> =
359
+ TModel extends keyof GroqChatModelProviderOptionsByName
360
+ ? GroqChatModelProviderOptionsByName[TModel]
361
+ : GroqTextProviderOptions
362
+
363
+ /**
364
+ * Resolve input modalities for a specific model.
365
+ * If the model has explicit modalities in the map, use those; otherwise use text only.
366
+ */
367
+ export type ResolveInputModalities<TModel extends string> =
368
+ TModel extends keyof GroqModelInputModalitiesByName
369
+ ? GroqModelInputModalitiesByName[TModel]
370
+ : readonly ['text']
@@ -0,0 +1,225 @@
1
+ import type {
2
+ ChatCompletionMessageParam,
3
+ ChatCompletionTool,
4
+ ChatCompletionToolChoiceOption,
5
+ CompoundCustom,
6
+ Document,
7
+ ResponseFormatJsonObject,
8
+ ResponseFormatJsonSchema,
9
+ ResponseFormatText,
10
+ SearchSettings,
11
+ } from '../message-types'
12
+
13
+ /**
14
+ * Groq-specific provider options for text/chat models.
15
+ *
16
+ * These options extend the standard Chat Completions API parameters
17
+ * with Groq-specific features like compound models and search settings.
18
+ *
19
+ * @see https://console.groq.com/docs/api-reference#chat
20
+ */
21
+ export interface GroqTextProviderOptions {
22
+ /**
23
+ * Whether to enable citations in the response. When enabled, the model will
24
+ * include citations for information retrieved from provided documents or web
25
+ * searches.
26
+ */
27
+ citation_options?: 'enabled' | 'disabled' | null
28
+
29
+ /** Custom configuration of models and tools for Compound. */
30
+ compound_custom?: CompoundCustom | null
31
+
32
+ /**
33
+ * If set to true, groq will return called tools without validating that the tool
34
+ * is present in request.tools. tool_choice=required/none will still be enforced,
35
+ * but the request cannot require a specific tool be used.
36
+ */
37
+ disable_tool_validation?: boolean
38
+
39
+ /**
40
+ * A list of documents to provide context for the conversation. Each document
41
+ * contains text that can be referenced by the model.
42
+ */
43
+ documents?: Array<Document> | null
44
+
45
+ /**
46
+ * Number between -2.0 and 2.0. Positive values penalize new tokens based on their
47
+ * existing frequency in the text so far, decreasing the model's likelihood to
48
+ * repeat the same line verbatim.
49
+ */
50
+ frequency_penalty?: number | null
51
+
52
+ /**
53
+ * Whether to include reasoning in the response. This field is mutually exclusive
54
+ * with `reasoning_format`.
55
+ */
56
+ include_reasoning?: boolean | null
57
+
58
+ /** Modify the likelihood of specified tokens appearing in the completion. */
59
+ logit_bias?: { [key: string]: number } | null
60
+
61
+ /**
62
+ * Whether to return log probabilities of the output tokens or not. If true,
63
+ * returns the log probabilities of each output token returned in the `content`
64
+ * of `message`.
65
+ */
66
+ logprobs?: boolean | null
67
+
68
+ /**
69
+ * The maximum number of tokens that can be generated in the chat completion. The
70
+ * total length of input tokens and generated tokens is limited by the model's
71
+ * context length.
72
+ */
73
+ max_completion_tokens?: number | null
74
+
75
+ /** Request metadata. */
76
+ metadata?: { [key: string]: string } | null
77
+
78
+ /**
79
+ * How many chat completion choices to generate for each input message.
80
+ * Currently only n=1 is supported.
81
+ */
82
+ n?: number | null
83
+
84
+ /** Whether to enable parallel function calling during tool use. */
85
+ parallel_tool_calls?: boolean | null
86
+
87
+ /**
88
+ * Number between -2.0 and 2.0. Positive values penalize new tokens based on
89
+ * whether they appear in the text so far, increasing the model's likelihood to
90
+ * talk about new topics.
91
+ */
92
+ presence_penalty?: number | null
93
+
94
+ /**
95
+ * Controls reasoning effort for supported models.
96
+ *
97
+ * - qwen3 models: `'none'` to disable, `'default'` or null to enable
98
+ * - openai/gpt-oss models: `'low'`, `'medium'` (default), or `'high'`
99
+ */
100
+ reasoning_effort?: 'none' | 'default' | 'low' | 'medium' | 'high' | null
101
+
102
+ /**
103
+ * Specifies how to output reasoning tokens.
104
+ * This field is mutually exclusive with `include_reasoning`.
105
+ */
106
+ reasoning_format?: 'hidden' | 'raw' | 'parsed' | null
107
+
108
+ /**
109
+ * An object specifying the format that the model must output.
110
+ *
111
+ * - `json_schema` — enables Structured Outputs (preferred)
112
+ * - `json_object` — enables the older JSON mode
113
+ * - `text` — plain text output (default)
114
+ *
115
+ * @see https://console.groq.com/docs/structured-outputs
116
+ */
117
+ response_format?:
118
+ | ResponseFormatText
119
+ | ResponseFormatJsonSchema
120
+ | ResponseFormatJsonObject
121
+ | null
122
+
123
+ /** Settings for web search functionality when the model uses a web search tool. */
124
+ search_settings?: SearchSettings | null
125
+
126
+ /**
127
+ * If specified, our system will make a best effort to sample deterministically,
128
+ * such that repeated requests with the same `seed` and parameters should return
129
+ * the same result.
130
+ */
131
+ seed?: number | null
132
+
133
+ /**
134
+ * The service tier to use for the request.
135
+ *
136
+ * - `auto` — automatically select the highest tier available
137
+ * - `flex` — uses the flex tier, which will succeed or fail quickly
138
+ */
139
+ service_tier?: 'auto' | 'on_demand' | 'flex' | 'performance' | null
140
+
141
+ /**
142
+ * Up to 4 sequences where the API will stop generating further tokens.
143
+ * The returned text will not contain the stop sequence.
144
+ */
145
+ stop?: string | null | Array<string>
146
+
147
+ /** Whether to store the request for future use. */
148
+ store?: boolean | null
149
+
150
+ /**
151
+ * Sampling temperature between 0 and 2. Higher values like 0.8 will make the
152
+ * output more random, while lower values like 0.2 will make it more focused
153
+ * and deterministic. We generally recommend altering this or top_p but not both.
154
+ */
155
+ temperature?: number | null
156
+
157
+ /**
158
+ * Controls which (if any) tool is called by the model.
159
+ *
160
+ * - `none` — never call tools
161
+ * - `auto` — model decides (default when tools are present)
162
+ * - `required` — model must call tools
163
+ * - Named choice — forces a specific tool
164
+ */
165
+ tool_choice?: ChatCompletionToolChoiceOption | null
166
+
167
+ /**
168
+ * An integer between 0 and 20 specifying the number of most likely tokens to
169
+ * return at each token position. `logprobs` must be set to `true` if this
170
+ * parameter is used.
171
+ */
172
+ top_logprobs?: number | null
173
+
174
+ /**
175
+ * An alternative to sampling with temperature, called nucleus sampling, where the
176
+ * model considers the results of the tokens with top_p probability mass. So 0.1
177
+ * means only the tokens comprising the top 10% probability mass are considered.
178
+ */
179
+ top_p?: number | null
180
+
181
+ /**
182
+ * A unique identifier representing your end-user, which can help monitor and
183
+ * detect abuse.
184
+ */
185
+ user?: string | null
186
+ }
187
+
188
+ /**
189
+ * Internal options interface used for validation within the adapter.
190
+ * Extends provider options with required fields for API requests.
191
+ */
192
+ export interface InternalTextProviderOptions extends GroqTextProviderOptions {
193
+ /** An array of messages comprising the conversation. */
194
+ messages: Array<ChatCompletionMessageParam>
195
+
196
+ /**
197
+ * The model name (e.g. "llama-3.3-70b-versatile", "openai/gpt-oss-120b").
198
+ * @see https://console.groq.com/docs/models
199
+ */
200
+ model: string
201
+
202
+ /** Whether to stream partial message deltas as server-sent events. */
203
+ stream?: boolean | null
204
+
205
+ /**
206
+ * Tools the model may call (functions, code_interpreter, etc).
207
+ * @see https://console.groq.com/docs/tool-use
208
+ */
209
+ tools?: Array<ChatCompletionTool>
210
+ }
211
+
212
+ /**
213
+ * External provider options (what users pass in)
214
+ */
215
+ export type ExternalTextProviderOptions = GroqTextProviderOptions
216
+
217
+ /**
218
+ * Validates text provider options.
219
+ * Basic validation stub — Groq API handles detailed validation.
220
+ */
221
+ export function validateTextProviderOptions(
222
+ _options: InternalTextProviderOptions,
223
+ ): void {
224
+ // Groq API handles detailed validation
225
+ }
@@ -0,0 +1,44 @@
1
+ import { makeGroqStructuredOutputCompatible } from '../utils/schema-converter'
2
+ import type { JSONSchema, Tool } from '@tanstack/ai'
3
+ import type { ChatCompletionTool } from '../message-types'
4
+
5
+ export type FunctionTool = ChatCompletionTool
6
+
7
+ /**
8
+ * Converts a standard Tool to Groq ChatCompletionTool format.
9
+ *
10
+ * Tool schemas are already converted to JSON Schema in the ai layer.
11
+ * We apply Groq-specific transformations for strict mode:
12
+ * - All properties in required array
13
+ * - Optional fields made nullable
14
+ * - additionalProperties: false
15
+ */
16
+ export function convertFunctionToolToAdapterFormat(tool: Tool): FunctionTool {
17
+ const inputSchema = (tool.inputSchema ?? {
18
+ type: 'object',
19
+ properties: {},
20
+ required: [],
21
+ }) as JSONSchema
22
+
23
+ // Ensure object schemas always have properties (e.g. z.object({}) may produce { type: 'object' } without properties)
24
+ if (inputSchema.type === 'object' && !inputSchema.properties) {
25
+ inputSchema.properties = {}
26
+ }
27
+
28
+ const jsonSchema = makeGroqStructuredOutputCompatible(
29
+ inputSchema,
30
+ inputSchema.required || [],
31
+ )
32
+
33
+ jsonSchema.additionalProperties = false
34
+
35
+ return {
36
+ type: 'function',
37
+ function: {
38
+ name: tool.name,
39
+ description: tool.description,
40
+ parameters: jsonSchema,
41
+ strict: true,
42
+ },
43
+ } satisfies FunctionTool
44
+ }
@@ -0,0 +1,5 @@
1
+ export {
2
+ convertFunctionToolToAdapterFormat,
3
+ type FunctionTool,
4
+ } from './function-tool'
5
+ export { convertToolsToProviderFormat } from './tool-converter'
@@ -0,0 +1,15 @@
1
+ import { convertFunctionToolToAdapterFormat } from './function-tool'
2
+ import type { FunctionTool } from './function-tool'
3
+ import type { Tool } from '@tanstack/ai'
4
+
5
+ /**
6
+ * Converts an array of standard Tools to Groq-specific format.
7
+ * Groq uses an OpenAI-compatible API, so we primarily support function tools.
8
+ */
9
+ export function convertToolsToProviderFormat(
10
+ tools: Array<Tool>,
11
+ ): Array<FunctionTool> {
12
+ return tools.map((tool) => {
13
+ return convertFunctionToolToAdapterFormat(tool)
14
+ })
15
+ }
@@ -0,0 +1,42 @@
1
+ import Groq_SDK from 'groq-sdk'
2
+ import type { ClientOptions } from 'groq-sdk'
3
+
4
+ export interface GroqClientConfig extends ClientOptions {
5
+ apiKey: string
6
+ }
7
+
8
+ /**
9
+ * Creates a Groq SDK client instance
10
+ */
11
+ export function createGroqClient(config: GroqClientConfig): Groq_SDK {
12
+ return new Groq_SDK(config)
13
+ }
14
+
15
+ /**
16
+ * Gets Groq API key from environment variables
17
+ * @throws Error if GROQ_API_KEY is not found
18
+ */
19
+ export function getGroqApiKeyFromEnv(): string {
20
+ const env =
21
+ typeof globalThis !== 'undefined' && (globalThis as any).window?.env
22
+ ? (globalThis as any).window.env
23
+ : typeof process !== 'undefined'
24
+ ? process.env
25
+ : undefined
26
+ const key = env?.GROQ_API_KEY
27
+
28
+ if (!key) {
29
+ throw new Error(
30
+ 'GROQ_API_KEY is required. Please set it in your environment variables or use the factory function with an explicit API key.',
31
+ )
32
+ }
33
+
34
+ return key
35
+ }
36
+
37
+ /**
38
+ * Generates a unique ID with a prefix
39
+ */
40
+ export function generateId(prefix: string): string {
41
+ return `${prefix}-${Date.now()}-${Math.random().toString(36).substring(7)}`
42
+ }