@tanstack/ai-groq 0.1.4 → 0.1.6

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.
@@ -1,8 +1,11 @@
1
1
  import { BaseTextAdapter, StructuredOutputOptions, StructuredOutputResult } from '@tanstack/ai/adapters';
2
- import { GROQ_CHAT_MODELS, ResolveInputModalities, ResolveProviderOptions } from '../model-meta.js';
3
- import { StreamChunk, TextOptions } from '@tanstack/ai';
2
+ import { GROQ_CHAT_MODELS, GroqChatModelToolCapabilitiesByName, ResolveInputModalities, ResolveProviderOptions } from '../model-meta.js';
3
+ import { Modality, StreamChunk, TextOptions } from '@tanstack/ai';
4
+ import { ExternalTextProviderOptions } from '../text/text-provider-options.js';
4
5
  import { GroqMessageMetadataByModality } from '../message-types.js';
5
6
  import { GroqClientConfig } from '../utils.js';
7
+ type GroqTextProviderOptions = ExternalTextProviderOptions;
8
+ type ResolveToolCapabilities<TModel extends string> = TModel extends keyof GroqChatModelToolCapabilitiesByName ? NonNullable<GroqChatModelToolCapabilitiesByName[TModel]> : readonly [];
6
9
  /**
7
10
  * Configuration for Groq text adapter
8
11
  */
@@ -18,12 +21,12 @@ export type { ExternalTextProviderOptions as GroqTextProviderOptions } from '../
18
21
  * Tree-shakeable adapter for Groq chat/text completion functionality.
19
22
  * Uses the Groq SDK which provides an OpenAI-compatible Chat Completions API.
20
23
  */
21
- export declare class GroqTextAdapter<TModel extends (typeof GROQ_CHAT_MODELS)[number]> extends BaseTextAdapter<TModel, ResolveProviderOptions<TModel>, ResolveInputModalities<TModel>, GroqMessageMetadataByModality> {
24
+ export declare class GroqTextAdapter<TModel extends (typeof GROQ_CHAT_MODELS)[number], TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>, TInputModalities extends ReadonlyArray<Modality> = ResolveInputModalities<TModel>, TToolCapabilities extends ReadonlyArray<string> = ResolveToolCapabilities<TModel>> extends BaseTextAdapter<TModel, TProviderOptions, TInputModalities, GroqMessageMetadataByModality, TToolCapabilities> {
22
25
  readonly kind: "text";
23
26
  readonly name: "groq";
24
27
  private client;
25
28
  constructor(config: GroqTextConfig, model: TModel);
26
- chatStream(options: TextOptions<ResolveProviderOptions<TModel>>): AsyncIterable<StreamChunk>;
29
+ chatStream(options: TextOptions<GroqTextProviderOptions>): AsyncIterable<StreamChunk>;
27
30
  /**
28
31
  * Generate structured output using Groq's JSON Schema response format.
29
32
  * Uses stream: false to get the complete response in one call.
@@ -36,7 +39,7 @@ export declare class GroqTextAdapter<TModel extends (typeof GROQ_CHAT_MODELS)[nu
36
39
  * The outputSchema is already JSON Schema (converted in the ai layer).
37
40
  * We apply Groq-specific transformations for structured output compatibility.
38
41
  */
39
- structuredOutput(options: StructuredOutputOptions<ResolveProviderOptions<TModel>>): Promise<StructuredOutputResult<unknown>>;
42
+ structuredOutput(options: StructuredOutputOptions<GroqTextProviderOptions>): Promise<StructuredOutputResult<unknown>>;
40
43
  /**
41
44
  * Processes streaming chunks from the Groq API and yields AG-UI stream events.
42
45
  * Handles text content deltas, tool call assembly, and lifecycle events.
@@ -3,6 +3,7 @@ import { validateTextProviderOptions } from "../text/text-provider-options.js";
3
3
  import { makeGroqStructuredOutputCompatible, transformNullsToUndefined } from "../utils/schema-converter.js";
4
4
  import { convertToolsToProviderFormat } from "../tools/tool-converter.js";
5
5
  import { createGroqClient, generateId, getGroqApiKeyFromEnv } from "../utils/client.js";
6
+ const asChunk = (chunk) => chunk;
6
7
  class GroqTextAdapter extends BaseTextAdapter {
7
8
  constructor(config, model) {
8
9
  super({}, model);
@@ -14,7 +15,8 @@ class GroqTextAdapter extends BaseTextAdapter {
14
15
  const requestParams = this.mapTextOptionsToGroq(options);
15
16
  const timestamp = Date.now();
16
17
  const aguiState = {
17
- runId: generateId(this.name),
18
+ runId: options.runId ?? generateId(this.name),
19
+ threadId: options.threadId ?? generateId(this.name),
18
20
  messageId: generateId(this.name),
19
21
  timestamp,
20
22
  hasEmittedRunStarted: false
@@ -29,23 +31,26 @@ class GroqTextAdapter extends BaseTextAdapter {
29
31
  const err = error;
30
32
  if (!aguiState.hasEmittedRunStarted) {
31
33
  aguiState.hasEmittedRunStarted = true;
32
- yield {
34
+ yield asChunk({
33
35
  type: "RUN_STARTED",
34
36
  runId: aguiState.runId,
37
+ threadId: aguiState.threadId,
35
38
  model: options.model,
36
39
  timestamp
37
- };
40
+ });
38
41
  }
39
- yield {
42
+ yield asChunk({
40
43
  type: "RUN_ERROR",
41
44
  runId: aguiState.runId,
42
45
  model: options.model,
43
46
  timestamp,
47
+ message: err.message || "Unknown error",
48
+ code: err.code,
44
49
  error: {
45
50
  message: err.message || "Unknown error",
46
51
  code: err.code
47
52
  }
48
- };
53
+ });
49
54
  console.error(">>> chatStream: Fatal error during response creation <<<");
50
55
  console.error(">>> Error message:", err.message);
51
56
  console.error(">>> Error stack:", err.stack);
@@ -120,12 +125,13 @@ class GroqTextAdapter extends BaseTextAdapter {
120
125
  if (!choice) continue;
121
126
  if (!aguiState.hasEmittedRunStarted) {
122
127
  aguiState.hasEmittedRunStarted = true;
123
- yield {
128
+ yield asChunk({
124
129
  type: "RUN_STARTED",
125
130
  runId: aguiState.runId,
131
+ threadId: aguiState.threadId,
126
132
  model: chunk.model || options.model,
127
133
  timestamp
128
- };
134
+ });
129
135
  }
130
136
  const delta = choice.delta;
131
137
  const deltaContent = delta.content;
@@ -133,23 +139,23 @@ class GroqTextAdapter extends BaseTextAdapter {
133
139
  if (deltaContent) {
134
140
  if (!hasEmittedTextMessageStart) {
135
141
  hasEmittedTextMessageStart = true;
136
- yield {
142
+ yield asChunk({
137
143
  type: "TEXT_MESSAGE_START",
138
144
  messageId: aguiState.messageId,
139
145
  model: chunk.model || options.model,
140
146
  timestamp,
141
147
  role: "assistant"
142
- };
148
+ });
143
149
  }
144
150
  accumulatedContent += deltaContent;
145
- yield {
151
+ yield asChunk({
146
152
  type: "TEXT_MESSAGE_CONTENT",
147
153
  messageId: aguiState.messageId,
148
154
  model: chunk.model || options.model,
149
155
  timestamp,
150
156
  delta: deltaContent,
151
157
  content: accumulatedContent
152
- };
158
+ });
153
159
  }
154
160
  if (deltaToolCalls) {
155
161
  for (const toolCallDelta of deltaToolCalls) {
@@ -174,23 +180,24 @@ class GroqTextAdapter extends BaseTextAdapter {
174
180
  }
175
181
  if (toolCall.id && toolCall.name && !toolCall.started) {
176
182
  toolCall.started = true;
177
- yield {
183
+ yield asChunk({
178
184
  type: "TOOL_CALL_START",
179
185
  toolCallId: toolCall.id,
186
+ toolCallName: toolCall.name,
180
187
  toolName: toolCall.name,
181
188
  model: chunk.model || options.model,
182
189
  timestamp,
183
190
  index
184
- };
191
+ });
185
192
  }
186
193
  if (toolCallDelta.function?.arguments && toolCall.started) {
187
- yield {
194
+ yield asChunk({
188
195
  type: "TOOL_CALL_ARGS",
189
196
  toolCallId: toolCall.id,
190
197
  model: chunk.model || options.model,
191
198
  timestamp,
192
199
  delta: toolCallDelta.function.arguments
193
- };
200
+ });
194
201
  }
195
202
  }
196
203
  }
@@ -206,29 +213,31 @@ class GroqTextAdapter extends BaseTextAdapter {
206
213
  } catch {
207
214
  parsedInput = {};
208
215
  }
209
- yield {
216
+ yield asChunk({
210
217
  type: "TOOL_CALL_END",
211
218
  toolCallId: toolCall.id,
219
+ toolCallName: toolCall.name,
212
220
  toolName: toolCall.name,
213
221
  model: chunk.model || options.model,
214
222
  timestamp,
215
223
  input: parsedInput
216
- };
224
+ });
217
225
  }
218
226
  }
219
227
  const computedFinishReason = choice.finish_reason === "tool_calls" || toolCallsInProgress.size > 0 ? "tool_calls" : choice.finish_reason === "length" ? "length" : "stop";
220
228
  if (hasEmittedTextMessageStart) {
221
- yield {
229
+ yield asChunk({
222
230
  type: "TEXT_MESSAGE_END",
223
231
  messageId: aguiState.messageId,
224
232
  model: chunk.model || options.model,
225
233
  timestamp
226
- };
234
+ });
227
235
  }
228
236
  const groqUsage = chunk.x_groq?.usage;
229
- yield {
237
+ yield asChunk({
230
238
  type: "RUN_FINISHED",
231
239
  runId: aguiState.runId,
240
+ threadId: aguiState.threadId,
232
241
  model: chunk.model || options.model,
233
242
  timestamp,
234
243
  usage: groqUsage ? {
@@ -237,22 +246,24 @@ class GroqTextAdapter extends BaseTextAdapter {
237
246
  totalTokens: groqUsage.total_tokens || 0
238
247
  } : void 0,
239
248
  finishReason: computedFinishReason
240
- };
249
+ });
241
250
  }
242
251
  }
243
252
  } catch (error) {
244
253
  const err = error;
245
254
  console.log("[Groq Adapter] Stream ended with error:", err.message);
246
- yield {
255
+ yield asChunk({
247
256
  type: "RUN_ERROR",
248
257
  runId: aguiState.runId,
249
258
  model: options.model,
250
259
  timestamp,
260
+ message: err.message || "Unknown error occurred",
261
+ code: err.code,
251
262
  error: {
252
263
  message: err.message || "Unknown error occurred",
253
264
  code: err.code
254
265
  }
255
- };
266
+ });
256
267
  }
257
268
  }
258
269
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"text.js","sources":["../../../src/adapters/text.ts"],"sourcesContent":["import { BaseTextAdapter } from '@tanstack/ai/adapters'\nimport { validateTextProviderOptions } from '../text/text-provider-options'\nimport { convertToolsToProviderFormat } from '../tools'\nimport {\n createGroqClient,\n generateId,\n getGroqApiKeyFromEnv,\n makeGroqStructuredOutputCompatible,\n transformNullsToUndefined,\n} from '../utils'\nimport type {\n GROQ_CHAT_MODELS,\n ResolveInputModalities,\n ResolveProviderOptions,\n} from '../model-meta'\nimport type {\n StructuredOutputOptions,\n StructuredOutputResult,\n} from '@tanstack/ai/adapters'\nimport type GROQ_SDK from 'groq-sdk'\nimport type { ChatCompletionCreateParamsStreaming } from 'groq-sdk/resources/chat/completions'\nimport type {\n ContentPart,\n ModelMessage,\n StreamChunk,\n TextOptions,\n} from '@tanstack/ai'\nimport type { InternalTextProviderOptions } from '../text/text-provider-options'\nimport type {\n ChatCompletionContentPart,\n ChatCompletionMessageParam,\n GroqImageMetadata,\n GroqMessageMetadataByModality,\n} from '../message-types'\nimport type { GroqClientConfig } from '../utils'\n\n/**\n * Configuration for Groq text adapter\n */\nexport interface GroqTextConfig extends GroqClientConfig {}\n\n/**\n * Alias for TextProviderOptions for external use\n */\nexport type { ExternalTextProviderOptions as GroqTextProviderOptions } from '../text/text-provider-options'\n\n/**\n * Groq Text (Chat) Adapter\n *\n * Tree-shakeable adapter for Groq chat/text completion functionality.\n * Uses the Groq SDK which provides an OpenAI-compatible Chat Completions API.\n */\nexport class GroqTextAdapter<\n TModel extends (typeof GROQ_CHAT_MODELS)[number],\n> extends BaseTextAdapter<\n TModel,\n ResolveProviderOptions<TModel>,\n ResolveInputModalities<TModel>,\n GroqMessageMetadataByModality\n> {\n readonly kind = 'text' as const\n readonly name = 'groq' as const\n\n private client: GROQ_SDK\n\n constructor(config: GroqTextConfig, model: TModel) {\n super({}, model)\n this.client = createGroqClient(config)\n }\n\n async *chatStream(\n options: TextOptions<ResolveProviderOptions<TModel>>,\n ): AsyncIterable<StreamChunk> {\n const requestParams = this.mapTextOptionsToGroq(options)\n const timestamp = Date.now()\n\n const aguiState = {\n runId: generateId(this.name),\n messageId: generateId(this.name),\n timestamp,\n hasEmittedRunStarted: false,\n }\n\n try {\n const stream = await this.client.chat.completions.create({\n ...requestParams,\n stream: true,\n })\n\n yield* this.processGroqStreamChunks(stream, options, aguiState)\n } catch (error: unknown) {\n const err = error as Error & { code?: string }\n\n if (!aguiState.hasEmittedRunStarted) {\n aguiState.hasEmittedRunStarted = true\n yield {\n type: 'RUN_STARTED',\n runId: aguiState.runId,\n model: options.model,\n timestamp,\n }\n }\n\n yield {\n type: 'RUN_ERROR',\n runId: aguiState.runId,\n model: options.model,\n timestamp,\n error: {\n message: err.message || 'Unknown error',\n code: err.code,\n },\n }\n\n console.error('>>> chatStream: Fatal error during response creation <<<')\n console.error('>>> Error message:', err.message)\n console.error('>>> Error stack:', err.stack)\n console.error('>>> Full error:', err)\n }\n }\n\n /**\n * Generate structured output using Groq's JSON Schema response format.\n * Uses stream: false to get the complete response in one call.\n *\n * Groq has strict requirements for structured output:\n * - All properties must be in the `required` array\n * - Optional fields should have null added to their type union\n * - additionalProperties must be false for all objects\n *\n * The outputSchema is already JSON Schema (converted in the ai layer).\n * We apply Groq-specific transformations for structured output compatibility.\n */\n async structuredOutput(\n options: StructuredOutputOptions<ResolveProviderOptions<TModel>>,\n ): Promise<StructuredOutputResult<unknown>> {\n const { chatOptions, outputSchema } = options\n const requestParams = this.mapTextOptionsToGroq(chatOptions)\n\n const jsonSchema = makeGroqStructuredOutputCompatible(\n outputSchema,\n outputSchema.required || [],\n )\n\n try {\n const response = await this.client.chat.completions.create({\n ...requestParams,\n stream: false,\n response_format: {\n type: 'json_schema',\n json_schema: {\n name: 'structured_output',\n schema: jsonSchema,\n strict: true,\n },\n },\n })\n\n const rawText = response.choices[0]?.message.content || ''\n\n let parsed: unknown\n try {\n parsed = JSON.parse(rawText)\n } catch {\n throw new Error(\n `Failed to parse structured output as JSON. Content: ${rawText.slice(0, 200)}${rawText.length > 200 ? '...' : ''}`,\n )\n }\n\n const transformed = transformNullsToUndefined(parsed)\n\n return {\n data: transformed,\n rawText,\n }\n } catch (error: unknown) {\n const err = error as Error\n console.error('>>> structuredOutput: Error during response creation <<<')\n console.error('>>> Error message:', err.message)\n throw error\n }\n }\n\n /**\n * Processes streaming chunks from the Groq API and yields AG-UI stream events.\n * Handles text content deltas, tool call assembly, and lifecycle events.\n */\n private async *processGroqStreamChunks(\n stream: AsyncIterable<GROQ_SDK.Chat.Completions.ChatCompletionChunk>,\n options: TextOptions,\n aguiState: {\n runId: string\n messageId: string\n timestamp: number\n hasEmittedRunStarted: boolean\n },\n ): AsyncIterable<StreamChunk> {\n let accumulatedContent = ''\n const timestamp = aguiState.timestamp\n let hasEmittedTextMessageStart = false\n\n const toolCallsInProgress = new Map<\n number,\n {\n id: string\n name: string\n arguments: string\n started: boolean\n }\n >()\n\n try {\n for await (const chunk of stream) {\n const choice = chunk.choices[0]\n\n if (!choice) continue\n\n if (!aguiState.hasEmittedRunStarted) {\n aguiState.hasEmittedRunStarted = true\n yield {\n type: 'RUN_STARTED',\n runId: aguiState.runId,\n model: chunk.model || options.model,\n timestamp,\n }\n }\n\n const delta = choice.delta\n const deltaContent = delta.content\n const deltaToolCalls = delta.tool_calls\n\n if (deltaContent) {\n if (!hasEmittedTextMessageStart) {\n hasEmittedTextMessageStart = true\n yield {\n type: 'TEXT_MESSAGE_START',\n messageId: aguiState.messageId,\n model: chunk.model || options.model,\n timestamp,\n role: 'assistant',\n }\n }\n\n accumulatedContent += deltaContent\n\n yield {\n type: 'TEXT_MESSAGE_CONTENT',\n messageId: aguiState.messageId,\n model: chunk.model || options.model,\n timestamp,\n delta: deltaContent,\n content: accumulatedContent,\n }\n }\n\n if (deltaToolCalls) {\n for (const toolCallDelta of deltaToolCalls) {\n const index = toolCallDelta.index\n\n if (!toolCallsInProgress.has(index)) {\n toolCallsInProgress.set(index, {\n id: toolCallDelta.id || '',\n name: toolCallDelta.function?.name || '',\n arguments: '',\n started: false,\n })\n }\n\n const toolCall = toolCallsInProgress.get(index)!\n\n if (toolCallDelta.id) {\n toolCall.id = toolCallDelta.id\n }\n if (toolCallDelta.function?.name) {\n toolCall.name = toolCallDelta.function.name\n }\n if (toolCallDelta.function?.arguments) {\n toolCall.arguments += toolCallDelta.function.arguments\n }\n\n if (toolCall.id && toolCall.name && !toolCall.started) {\n toolCall.started = true\n yield {\n type: 'TOOL_CALL_START',\n toolCallId: toolCall.id,\n toolName: toolCall.name,\n model: chunk.model || options.model,\n timestamp,\n index,\n }\n }\n\n if (toolCallDelta.function?.arguments && toolCall.started) {\n yield {\n type: 'TOOL_CALL_ARGS',\n toolCallId: toolCall.id,\n model: chunk.model || options.model,\n timestamp,\n delta: toolCallDelta.function.arguments,\n }\n }\n }\n }\n\n if (choice.finish_reason) {\n if (\n choice.finish_reason === 'tool_calls' ||\n toolCallsInProgress.size > 0\n ) {\n for (const [, toolCall] of toolCallsInProgress) {\n if (!toolCall.started || !toolCall.id || !toolCall.name) {\n continue\n }\n\n let parsedInput: unknown = {}\n try {\n parsedInput = toolCall.arguments\n ? JSON.parse(toolCall.arguments)\n : {}\n } catch {\n parsedInput = {}\n }\n\n yield {\n type: 'TOOL_CALL_END',\n toolCallId: toolCall.id,\n toolName: toolCall.name,\n model: chunk.model || options.model,\n timestamp,\n input: parsedInput,\n }\n }\n }\n\n const computedFinishReason =\n choice.finish_reason === 'tool_calls' ||\n toolCallsInProgress.size > 0\n ? 'tool_calls'\n : choice.finish_reason === 'length'\n ? 'length'\n : 'stop'\n\n if (hasEmittedTextMessageStart) {\n yield {\n type: 'TEXT_MESSAGE_END',\n messageId: aguiState.messageId,\n model: chunk.model || options.model,\n timestamp,\n }\n }\n\n const groqUsage = chunk.x_groq?.usage\n\n yield {\n type: 'RUN_FINISHED',\n runId: aguiState.runId,\n model: chunk.model || options.model,\n timestamp,\n usage: groqUsage\n ? {\n promptTokens: groqUsage.prompt_tokens || 0,\n completionTokens: groqUsage.completion_tokens || 0,\n totalTokens: groqUsage.total_tokens || 0,\n }\n : undefined,\n finishReason: computedFinishReason,\n }\n }\n }\n } catch (error: unknown) {\n const err = error as Error & { code?: string }\n console.log('[Groq Adapter] Stream ended with error:', err.message)\n\n yield {\n type: 'RUN_ERROR',\n runId: aguiState.runId,\n model: options.model,\n timestamp,\n error: {\n message: err.message || 'Unknown error occurred',\n code: err.code,\n },\n }\n }\n }\n\n /**\n * Maps common TextOptions to Groq-specific Chat Completions request parameters.\n */\n private mapTextOptionsToGroq(\n options: TextOptions,\n ): ChatCompletionCreateParamsStreaming {\n const modelOptions = options.modelOptions as\n | Omit<\n InternalTextProviderOptions,\n 'max_tokens' | 'tools' | 'temperature' | 'input' | 'top_p'\n >\n | undefined\n\n if (modelOptions) {\n validateTextProviderOptions({\n ...modelOptions,\n model: options.model,\n })\n }\n\n const tools = options.tools\n ? convertToolsToProviderFormat(options.tools)\n : undefined\n\n const messages: Array<ChatCompletionMessageParam> = []\n\n if (options.systemPrompts && options.systemPrompts.length > 0) {\n messages.push({\n role: 'system',\n content: options.systemPrompts.join('\\n'),\n })\n }\n\n for (const message of options.messages) {\n messages.push(this.convertMessageToGroq(message))\n }\n\n return {\n model: options.model,\n messages,\n temperature: options.temperature,\n max_tokens: options.maxTokens,\n top_p: options.topP,\n tools,\n stream: true,\n }\n }\n\n /**\n * Converts a TanStack AI ModelMessage to a Groq ChatCompletionMessageParam.\n * Handles tool, assistant, and user messages including multimodal content.\n */\n private convertMessageToGroq(\n message: ModelMessage,\n ): ChatCompletionMessageParam {\n if (message.role === 'tool') {\n return {\n role: 'tool',\n tool_call_id: message.toolCallId || '',\n content:\n typeof message.content === 'string'\n ? message.content\n : JSON.stringify(message.content),\n }\n }\n\n if (message.role === 'assistant') {\n const toolCalls = message.toolCalls?.map((tc) => ({\n id: tc.id,\n type: 'function' as const,\n function: {\n name: tc.function.name,\n arguments:\n typeof tc.function.arguments === 'string'\n ? tc.function.arguments\n : JSON.stringify(tc.function.arguments),\n },\n }))\n\n return {\n role: 'assistant',\n content: this.extractTextContent(message.content),\n ...(toolCalls && toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),\n }\n }\n\n const contentParts = this.normalizeContent(message.content)\n\n if (contentParts.length === 1 && contentParts[0]?.type === 'text') {\n return {\n role: 'user',\n content: contentParts[0].content,\n }\n }\n\n const parts: Array<ChatCompletionContentPart> = []\n for (const part of contentParts) {\n if (part.type === 'text') {\n parts.push({ type: 'text', text: part.content })\n } else if (part.type === 'image') {\n const imageMetadata = part.metadata as GroqImageMetadata | undefined\n const imageValue = part.source.value\n const imageUrl =\n part.source.type === 'data' && !imageValue.startsWith('data:')\n ? `data:${part.source.mimeType};base64,${imageValue}`\n : imageValue\n parts.push({\n type: 'image_url',\n image_url: {\n url: imageUrl,\n detail: imageMetadata?.detail || 'auto',\n },\n })\n }\n }\n\n return {\n role: 'user',\n content: parts.length > 0 ? parts : '',\n }\n }\n\n /**\n * Normalizes message content to an array of ContentPart.\n * Handles backward compatibility with string content.\n */\n private normalizeContent(\n content: string | null | Array<ContentPart>,\n ): Array<ContentPart> {\n if (content === null) {\n return []\n }\n if (typeof content === 'string') {\n return [{ type: 'text', content: content }]\n }\n return content\n }\n\n /**\n * Extracts text content from a content value that may be string, null, or ContentPart array.\n */\n private extractTextContent(\n content: string | null | Array<ContentPart>,\n ): string {\n if (content === null) {\n return ''\n }\n if (typeof content === 'string') {\n return content\n }\n return content\n .filter((p) => p.type === 'text')\n .map((p) => p.content)\n .join('')\n }\n}\n\n/**\n * Creates a Groq text adapter with explicit API key.\n * Type resolution happens here at the call site.\n *\n * @param model - The model name (e.g., 'llama-3.3-70b-versatile', 'openai/gpt-oss-120b')\n * @param apiKey - Your Groq API key\n * @param config - Optional additional configuration\n * @returns Configured Groq text adapter instance with resolved types\n *\n * @example\n * ```typescript\n * const adapter = createGroqText('llama-3.3-70b-versatile', \"gsk_...\");\n * // adapter has type-safe providerOptions for llama-3.3-70b-versatile\n * ```\n */\nexport function createGroqText<\n TModel extends (typeof GROQ_CHAT_MODELS)[number],\n>(\n model: TModel,\n apiKey: string,\n config?: Omit<GroqTextConfig, 'apiKey'>,\n): GroqTextAdapter<TModel> {\n return new GroqTextAdapter({ apiKey, ...config }, model)\n}\n\n/**\n * Creates a Groq text adapter with automatic API key detection from environment variables.\n * Type resolution happens here at the call site.\n *\n * Looks for `GROQ_API_KEY` in:\n * - `process.env` (Node.js)\n * - `window.env` (Browser with injected env)\n *\n * @param model - The model name (e.g., 'llama-3.3-70b-versatile', 'openai/gpt-oss-120b')\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Groq text adapter instance with resolved types\n * @throws Error if GROQ_API_KEY is not found in environment\n *\n * @example\n * ```typescript\n * // Automatically uses GROQ_API_KEY from environment\n * const adapter = groqText('llama-3.3-70b-versatile');\n *\n * const stream = chat({\n * adapter,\n * messages: [{ role: \"user\", content: \"Hello!\" }]\n * });\n * ```\n */\nexport function groqText<TModel extends (typeof GROQ_CHAT_MODELS)[number]>(\n model: TModel,\n config?: Omit<GroqTextConfig, 'apiKey'>,\n): GroqTextAdapter<TModel> {\n const apiKey = getGroqApiKeyFromEnv()\n return createGroqText(model, apiKey, config)\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"text.js","sources":["../../../src/adapters/text.ts"],"sourcesContent":["import { BaseTextAdapter } from '@tanstack/ai/adapters'\nimport { validateTextProviderOptions } from '../text/text-provider-options'\nimport { convertToolsToProviderFormat } from '../tools'\nimport {\n createGroqClient,\n generateId,\n getGroqApiKeyFromEnv,\n makeGroqStructuredOutputCompatible,\n transformNullsToUndefined,\n} from '../utils'\nimport type {\n GROQ_CHAT_MODELS,\n GroqChatModelToolCapabilitiesByName,\n ResolveInputModalities,\n ResolveProviderOptions,\n} from '../model-meta'\nimport type {\n StructuredOutputOptions,\n StructuredOutputResult,\n} from '@tanstack/ai/adapters'\nimport type GROQ_SDK from 'groq-sdk'\nimport type { ChatCompletionCreateParamsStreaming } from 'groq-sdk/resources/chat/completions'\nimport type {\n ContentPart,\n Modality,\n ModelMessage,\n StreamChunk,\n TextOptions,\n} from '@tanstack/ai'\nimport type {\n ExternalTextProviderOptions,\n InternalTextProviderOptions,\n} from '../text/text-provider-options'\nimport type {\n ChatCompletionContentPart,\n ChatCompletionMessageParam,\n GroqImageMetadata,\n GroqMessageMetadataByModality,\n} from '../message-types'\nimport type { GroqClientConfig } from '../utils'\n\ntype GroqTextProviderOptions = ExternalTextProviderOptions\n\ntype ResolveToolCapabilities<TModel extends string> =\n TModel extends keyof GroqChatModelToolCapabilitiesByName\n ? NonNullable<GroqChatModelToolCapabilitiesByName[TModel]>\n : readonly []\n\n/** Cast an event object to StreamChunk. Adapters construct events with string\n * literal types which are structurally compatible with the EventType enum. */\nconst asChunk = (chunk: Record<string, unknown>) =>\n chunk as unknown as StreamChunk\n\n/**\n * Configuration for Groq text adapter\n */\nexport interface GroqTextConfig extends GroqClientConfig {}\n\n/**\n * Alias for TextProviderOptions for external use\n */\nexport type { ExternalTextProviderOptions as GroqTextProviderOptions } from '../text/text-provider-options'\n\n/**\n * Groq Text (Chat) Adapter\n *\n * Tree-shakeable adapter for Groq chat/text completion functionality.\n * Uses the Groq SDK which provides an OpenAI-compatible Chat Completions API.\n */\nexport class GroqTextAdapter<\n TModel extends (typeof GROQ_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 BaseTextAdapter<\n TModel,\n TProviderOptions,\n TInputModalities,\n GroqMessageMetadataByModality,\n TToolCapabilities\n> {\n readonly kind = 'text' as const\n readonly name = 'groq' as const\n\n private client: GROQ_SDK\n\n constructor(config: GroqTextConfig, model: TModel) {\n super({}, model)\n this.client = createGroqClient(config)\n }\n\n async *chatStream(\n options: TextOptions<GroqTextProviderOptions>,\n ): AsyncIterable<StreamChunk> {\n const requestParams = this.mapTextOptionsToGroq(options)\n const timestamp = Date.now()\n\n const aguiState = {\n runId: options.runId ?? generateId(this.name),\n threadId: options.threadId ?? generateId(this.name),\n messageId: generateId(this.name),\n timestamp,\n hasEmittedRunStarted: false,\n }\n\n try {\n const stream = await this.client.chat.completions.create({\n ...requestParams,\n stream: true,\n })\n\n yield* this.processGroqStreamChunks(stream, options, aguiState)\n } catch (error: unknown) {\n const err = error as Error & { code?: string }\n\n if (!aguiState.hasEmittedRunStarted) {\n aguiState.hasEmittedRunStarted = true\n yield asChunk({\n type: 'RUN_STARTED',\n runId: aguiState.runId,\n threadId: aguiState.threadId,\n model: options.model,\n timestamp,\n })\n }\n\n yield asChunk({\n type: 'RUN_ERROR',\n runId: aguiState.runId,\n model: options.model,\n timestamp,\n message: err.message || 'Unknown error',\n code: err.code,\n error: {\n message: err.message || 'Unknown error',\n code: err.code,\n },\n })\n\n console.error('>>> chatStream: Fatal error during response creation <<<')\n console.error('>>> Error message:', err.message)\n console.error('>>> Error stack:', err.stack)\n console.error('>>> Full error:', err)\n }\n }\n\n /**\n * Generate structured output using Groq's JSON Schema response format.\n * Uses stream: false to get the complete response in one call.\n *\n * Groq has strict requirements for structured output:\n * - All properties must be in the `required` array\n * - Optional fields should have null added to their type union\n * - additionalProperties must be false for all objects\n *\n * The outputSchema is already JSON Schema (converted in the ai layer).\n * We apply Groq-specific transformations for structured output compatibility.\n */\n async structuredOutput(\n options: StructuredOutputOptions<GroqTextProviderOptions>,\n ): Promise<StructuredOutputResult<unknown>> {\n const { chatOptions, outputSchema } = options\n const requestParams = this.mapTextOptionsToGroq(chatOptions)\n\n const jsonSchema = makeGroqStructuredOutputCompatible(\n outputSchema,\n outputSchema.required || [],\n )\n\n try {\n const response = await this.client.chat.completions.create({\n ...requestParams,\n stream: false,\n response_format: {\n type: 'json_schema',\n json_schema: {\n name: 'structured_output',\n schema: jsonSchema,\n strict: true,\n },\n },\n })\n\n const rawText = response.choices[0]?.message.content || ''\n\n let parsed: unknown\n try {\n parsed = JSON.parse(rawText)\n } catch {\n throw new Error(\n `Failed to parse structured output as JSON. Content: ${rawText.slice(0, 200)}${rawText.length > 200 ? '...' : ''}`,\n )\n }\n\n const transformed = transformNullsToUndefined(parsed)\n\n return {\n data: transformed,\n rawText,\n }\n } catch (error: unknown) {\n const err = error as Error\n console.error('>>> structuredOutput: Error during response creation <<<')\n console.error('>>> Error message:', err.message)\n throw error\n }\n }\n\n /**\n * Processes streaming chunks from the Groq API and yields AG-UI stream events.\n * Handles text content deltas, tool call assembly, and lifecycle events.\n */\n private async *processGroqStreamChunks(\n stream: AsyncIterable<GROQ_SDK.Chat.Completions.ChatCompletionChunk>,\n options: TextOptions,\n aguiState: {\n runId: string\n threadId: string\n messageId: string\n timestamp: number\n hasEmittedRunStarted: boolean\n },\n ): AsyncIterable<StreamChunk> {\n let accumulatedContent = ''\n const timestamp = aguiState.timestamp\n let hasEmittedTextMessageStart = false\n\n const toolCallsInProgress = new Map<\n number,\n {\n id: string\n name: string\n arguments: string\n started: boolean\n }\n >()\n\n try {\n for await (const chunk of stream) {\n const choice = chunk.choices[0]\n\n if (!choice) continue\n\n if (!aguiState.hasEmittedRunStarted) {\n aguiState.hasEmittedRunStarted = true\n yield asChunk({\n type: 'RUN_STARTED',\n runId: aguiState.runId,\n threadId: aguiState.threadId,\n model: chunk.model || options.model,\n timestamp,\n })\n }\n\n const delta = choice.delta\n const deltaContent = delta.content\n const deltaToolCalls = delta.tool_calls\n\n if (deltaContent) {\n if (!hasEmittedTextMessageStart) {\n hasEmittedTextMessageStart = true\n yield asChunk({\n type: 'TEXT_MESSAGE_START',\n messageId: aguiState.messageId,\n model: chunk.model || options.model,\n timestamp,\n role: 'assistant',\n })\n }\n\n accumulatedContent += deltaContent\n\n yield asChunk({\n type: 'TEXT_MESSAGE_CONTENT',\n messageId: aguiState.messageId,\n model: chunk.model || options.model,\n timestamp,\n delta: deltaContent,\n content: accumulatedContent,\n })\n }\n\n if (deltaToolCalls) {\n for (const toolCallDelta of deltaToolCalls) {\n const index = toolCallDelta.index\n\n if (!toolCallsInProgress.has(index)) {\n toolCallsInProgress.set(index, {\n id: toolCallDelta.id || '',\n name: toolCallDelta.function?.name || '',\n arguments: '',\n started: false,\n })\n }\n\n const toolCall = toolCallsInProgress.get(index)!\n\n if (toolCallDelta.id) {\n toolCall.id = toolCallDelta.id\n }\n if (toolCallDelta.function?.name) {\n toolCall.name = toolCallDelta.function.name\n }\n if (toolCallDelta.function?.arguments) {\n toolCall.arguments += toolCallDelta.function.arguments\n }\n\n if (toolCall.id && toolCall.name && !toolCall.started) {\n toolCall.started = true\n yield asChunk({\n type: 'TOOL_CALL_START',\n toolCallId: toolCall.id,\n toolCallName: toolCall.name,\n toolName: toolCall.name,\n model: chunk.model || options.model,\n timestamp,\n index,\n })\n }\n\n if (toolCallDelta.function?.arguments && toolCall.started) {\n yield asChunk({\n type: 'TOOL_CALL_ARGS',\n toolCallId: toolCall.id,\n model: chunk.model || options.model,\n timestamp,\n delta: toolCallDelta.function.arguments,\n })\n }\n }\n }\n\n if (choice.finish_reason) {\n if (\n choice.finish_reason === 'tool_calls' ||\n toolCallsInProgress.size > 0\n ) {\n for (const [, toolCall] of toolCallsInProgress) {\n if (!toolCall.started || !toolCall.id || !toolCall.name) {\n continue\n }\n\n let parsedInput: unknown = {}\n try {\n parsedInput = toolCall.arguments\n ? JSON.parse(toolCall.arguments)\n : {}\n } catch {\n parsedInput = {}\n }\n\n yield asChunk({\n type: 'TOOL_CALL_END',\n toolCallId: toolCall.id,\n toolCallName: toolCall.name,\n toolName: toolCall.name,\n model: chunk.model || options.model,\n timestamp,\n input: parsedInput,\n })\n }\n }\n\n const computedFinishReason =\n choice.finish_reason === 'tool_calls' ||\n toolCallsInProgress.size > 0\n ? 'tool_calls'\n : choice.finish_reason === 'length'\n ? 'length'\n : 'stop'\n\n if (hasEmittedTextMessageStart) {\n yield asChunk({\n type: 'TEXT_MESSAGE_END',\n messageId: aguiState.messageId,\n model: chunk.model || options.model,\n timestamp,\n })\n }\n\n const groqUsage = chunk.x_groq?.usage\n\n yield asChunk({\n type: 'RUN_FINISHED',\n runId: aguiState.runId,\n threadId: aguiState.threadId,\n model: chunk.model || options.model,\n timestamp,\n usage: groqUsage\n ? {\n promptTokens: groqUsage.prompt_tokens || 0,\n completionTokens: groqUsage.completion_tokens || 0,\n totalTokens: groqUsage.total_tokens || 0,\n }\n : undefined,\n finishReason: computedFinishReason,\n })\n }\n }\n } catch (error: unknown) {\n const err = error as Error & { code?: string }\n console.log('[Groq Adapter] Stream ended with error:', err.message)\n\n yield asChunk({\n type: 'RUN_ERROR',\n runId: aguiState.runId,\n model: options.model,\n timestamp,\n message: err.message || 'Unknown error occurred',\n code: err.code,\n error: {\n message: err.message || 'Unknown error occurred',\n code: err.code,\n },\n })\n }\n }\n\n /**\n * Maps common TextOptions to Groq-specific Chat Completions request parameters.\n */\n private mapTextOptionsToGroq(\n options: TextOptions,\n ): ChatCompletionCreateParamsStreaming {\n const modelOptions = options.modelOptions as\n | Omit<\n InternalTextProviderOptions,\n 'max_tokens' | 'tools' | 'temperature' | 'input' | 'top_p'\n >\n | undefined\n\n if (modelOptions) {\n validateTextProviderOptions({\n ...modelOptions,\n model: options.model,\n })\n }\n\n const tools = options.tools\n ? convertToolsToProviderFormat(options.tools)\n : undefined\n\n const messages: Array<ChatCompletionMessageParam> = []\n\n if (options.systemPrompts && options.systemPrompts.length > 0) {\n messages.push({\n role: 'system',\n content: options.systemPrompts.join('\\n'),\n })\n }\n\n for (const message of options.messages) {\n messages.push(this.convertMessageToGroq(message))\n }\n\n return {\n model: options.model,\n messages,\n temperature: options.temperature,\n max_tokens: options.maxTokens,\n top_p: options.topP,\n tools,\n stream: true,\n }\n }\n\n /**\n * Converts a TanStack AI ModelMessage to a Groq ChatCompletionMessageParam.\n * Handles tool, assistant, and user messages including multimodal content.\n */\n private convertMessageToGroq(\n message: ModelMessage,\n ): ChatCompletionMessageParam {\n if (message.role === 'tool') {\n return {\n role: 'tool',\n tool_call_id: message.toolCallId || '',\n content:\n typeof message.content === 'string'\n ? message.content\n : JSON.stringify(message.content),\n }\n }\n\n if (message.role === 'assistant') {\n const toolCalls = message.toolCalls?.map((tc) => ({\n id: tc.id,\n type: 'function' as const,\n function: {\n name: tc.function.name,\n arguments:\n typeof tc.function.arguments === 'string'\n ? tc.function.arguments\n : JSON.stringify(tc.function.arguments),\n },\n }))\n\n return {\n role: 'assistant',\n content: this.extractTextContent(message.content),\n ...(toolCalls && toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),\n }\n }\n\n const contentParts = this.normalizeContent(message.content)\n\n if (contentParts.length === 1 && contentParts[0]?.type === 'text') {\n return {\n role: 'user',\n content: contentParts[0].content,\n }\n }\n\n const parts: Array<ChatCompletionContentPart> = []\n for (const part of contentParts) {\n if (part.type === 'text') {\n parts.push({ type: 'text', text: part.content })\n } else if (part.type === 'image') {\n const imageMetadata = part.metadata as GroqImageMetadata | undefined\n const imageValue = part.source.value\n const imageUrl =\n part.source.type === 'data' && !imageValue.startsWith('data:')\n ? `data:${part.source.mimeType};base64,${imageValue}`\n : imageValue\n parts.push({\n type: 'image_url',\n image_url: {\n url: imageUrl,\n detail: imageMetadata?.detail || 'auto',\n },\n })\n }\n }\n\n return {\n role: 'user',\n content: parts.length > 0 ? parts : '',\n }\n }\n\n /**\n * Normalizes message content to an array of ContentPart.\n * Handles backward compatibility with string content.\n */\n private normalizeContent(\n content: string | null | Array<ContentPart>,\n ): Array<ContentPart> {\n if (content === null) {\n return []\n }\n if (typeof content === 'string') {\n return [{ type: 'text', content: content }]\n }\n return content\n }\n\n /**\n * Extracts text content from a content value that may be string, null, or ContentPart array.\n */\n private extractTextContent(\n content: string | null | Array<ContentPart>,\n ): string {\n if (content === null) {\n return ''\n }\n if (typeof content === 'string') {\n return content\n }\n return content\n .filter((p) => p.type === 'text')\n .map((p) => p.content)\n .join('')\n }\n}\n\n/**\n * Creates a Groq text adapter with explicit API key.\n * Type resolution happens here at the call site.\n *\n * @param model - The model name (e.g., 'llama-3.3-70b-versatile', 'openai/gpt-oss-120b')\n * @param apiKey - Your Groq API key\n * @param config - Optional additional configuration\n * @returns Configured Groq text adapter instance with resolved types\n *\n * @example\n * ```typescript\n * const adapter = createGroqText('llama-3.3-70b-versatile', \"gsk_...\");\n * // adapter has type-safe providerOptions for llama-3.3-70b-versatile\n * ```\n */\nexport function createGroqText<\n TModel extends (typeof GROQ_CHAT_MODELS)[number],\n>(\n model: TModel,\n apiKey: string,\n config?: Omit<GroqTextConfig, 'apiKey'>,\n): GroqTextAdapter<TModel> {\n return new GroqTextAdapter({ apiKey, ...config }, model)\n}\n\n/**\n * Creates a Groq text adapter with automatic API key detection from environment variables.\n * Type resolution happens here at the call site.\n *\n * Looks for `GROQ_API_KEY` in:\n * - `process.env` (Node.js)\n * - `window.env` (Browser with injected env)\n *\n * @param model - The model name (e.g., 'llama-3.3-70b-versatile', 'openai/gpt-oss-120b')\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Groq text adapter instance with resolved types\n * @throws Error if GROQ_API_KEY is not found in environment\n *\n * @example\n * ```typescript\n * // Automatically uses GROQ_API_KEY from environment\n * const adapter = groqText('llama-3.3-70b-versatile');\n *\n * const stream = chat({\n * adapter,\n * messages: [{ role: \"user\", content: \"Hello!\" }]\n * });\n * ```\n */\nexport function groqText<TModel extends (typeof GROQ_CHAT_MODELS)[number]>(\n model: TModel,\n config?: Omit<GroqTextConfig, 'apiKey'>,\n): GroqTextAdapter<TModel> {\n const apiKey = getGroqApiKeyFromEnv()\n return createGroqText(model, apiKey, config)\n}\n"],"names":[],"mappings":"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"}
@@ -5,6 +5,6 @@
5
5
  * Provides tree-shakeable adapters for Groq's Chat Completions API.
6
6
  */
7
7
  export { GroqTextAdapter, createGroqText, groqText, type GroqTextConfig, type GroqTextProviderOptions, } from './adapters/text.js';
8
- export type { GroqChatModelProviderOptionsByName, GroqModelInputModalitiesByName, ResolveProviderOptions, ResolveInputModalities, GroqChatModels, } from './model-meta.js';
8
+ export type { GroqChatModelProviderOptionsByName, GroqChatModelToolCapabilitiesByName, GroqModelInputModalitiesByName, ResolveProviderOptions, ResolveInputModalities, GroqChatModels, } from './model-meta.js';
9
9
  export { GROQ_CHAT_MODELS } from './model-meta.js';
10
10
  export type { GroqTextMetadata, GroqImageMetadata, GroqAudioMetadata, GroqVideoMetadata, GroqDocumentMetadata, GroqMessageMetadataByModality, } from './message-types.js';
@@ -16,6 +16,7 @@ declare const LLAMA_3_3_70B_VERSATILE: {
16
16
  readonly output: ["text"];
17
17
  readonly endpoints: ["chat"];
18
18
  readonly features: ["streaming", "tools", "json_object"];
19
+ readonly tools: readonly [];
19
20
  };
20
21
  };
21
22
  declare const LLAMA_4_MAVERICK_17B_128E_INSTRUCT: {
@@ -35,6 +36,7 @@ declare const LLAMA_4_MAVERICK_17B_128E_INSTRUCT: {
35
36
  readonly output: ["text"];
36
37
  readonly endpoints: ["chat"];
37
38
  readonly features: ["streaming", "tools", "json_object", "json_schema", "vision"];
39
+ readonly tools: readonly [];
38
40
  };
39
41
  };
40
42
  declare const LLAMA_4_SCOUT_17B_16E_INSTRUCT: {
@@ -54,6 +56,7 @@ declare const LLAMA_4_SCOUT_17B_16E_INSTRUCT: {
54
56
  readonly output: ["text"];
55
57
  readonly endpoints: ["chat"];
56
58
  readonly features: ["streaming", "tools", "json_object"];
59
+ readonly tools: readonly [];
57
60
  };
58
61
  };
59
62
  declare const LLAMA_GUARD_4_12B: {
@@ -73,6 +76,7 @@ declare const LLAMA_GUARD_4_12B: {
73
76
  readonly output: ["text"];
74
77
  readonly endpoints: ["chat"];
75
78
  readonly features: ["streaming", "json_object", "content_moderation", "vision"];
79
+ readonly tools: readonly [];
76
80
  };
77
81
  };
78
82
  declare const LLAMA_PROMPT_GUARD_2_86M: {
@@ -92,6 +96,7 @@ declare const LLAMA_PROMPT_GUARD_2_86M: {
92
96
  readonly output: ["text"];
93
97
  readonly endpoints: ["chat"];
94
98
  readonly features: ["streaming", "content_moderation", "json_object"];
99
+ readonly tools: readonly [];
95
100
  };
96
101
  };
97
102
  declare const LLAMA_3_1_8B_INSTANT: {
@@ -111,6 +116,7 @@ declare const LLAMA_3_1_8B_INSTANT: {
111
116
  readonly output: ["text"];
112
117
  readonly endpoints: ["chat"];
113
118
  readonly features: ["streaming", "json_object", "tools"];
119
+ readonly tools: readonly [];
114
120
  };
115
121
  };
116
122
  declare const LLAMA_PROMPT_GUARD_2_22M: {
@@ -130,6 +136,7 @@ declare const LLAMA_PROMPT_GUARD_2_22M: {
130
136
  readonly output: ["text"];
131
137
  readonly endpoints: ["chat"];
132
138
  readonly features: ["streaming", "content_moderation"];
139
+ readonly tools: readonly [];
133
140
  };
134
141
  };
135
142
  declare const GPT_OSS_120B: {
@@ -150,6 +157,7 @@ declare const GPT_OSS_120B: {
150
157
  readonly output: ["text"];
151
158
  readonly endpoints: ["chat"];
152
159
  readonly features: ["streaming", "json_object", "json_schema", "tools", "browser_search", "code_execution", "reasoning"];
160
+ readonly tools: readonly [];
153
161
  };
154
162
  };
155
163
  declare const GPT_OSS_SAFEGUARD_20B: {
@@ -170,6 +178,7 @@ declare const GPT_OSS_SAFEGUARD_20B: {
170
178
  readonly output: ["text"];
171
179
  readonly endpoints: ["chat"];
172
180
  readonly features: ["streaming", "tools", "browser_search", "code_execution", "json_object", "json_schema", "reasoning", "content_moderation"];
181
+ readonly tools: readonly [];
173
182
  };
174
183
  };
175
184
  declare const GPT_OSS_20B: {
@@ -190,6 +199,7 @@ declare const GPT_OSS_20B: {
190
199
  readonly output: ["text"];
191
200
  readonly endpoints: ["chat"];
192
201
  readonly features: ["streaming", "browser_search", "code_execution", "json_object", "json_schema", "reasoning", "tools"];
202
+ readonly tools: readonly [];
193
203
  };
194
204
  };
195
205
  declare const KIMI_K2_INSTRUCT_0905: {
@@ -210,6 +220,7 @@ declare const KIMI_K2_INSTRUCT_0905: {
210
220
  readonly output: ["text"];
211
221
  readonly endpoints: ["chat"];
212
222
  readonly features: ["streaming", "tools", "json_object", "json_schema"];
223
+ readonly tools: readonly [];
213
224
  };
214
225
  };
215
226
  declare const QWEN3_32B: {
@@ -229,6 +240,7 @@ declare const QWEN3_32B: {
229
240
  readonly output: ["text"];
230
241
  readonly endpoints: ["chat"];
231
242
  readonly features: ["streaming", "json_object", "tools", "reasoning"];
243
+ readonly tools: readonly [];
232
244
  };
233
245
  };
234
246
  /**
@@ -262,6 +274,26 @@ export type GroqModelInputModalitiesByName = {
262
274
  export type GroqChatModelProviderOptionsByName = {
263
275
  [K in (typeof GROQ_CHAT_MODELS)[number]]: GroqTextProviderOptions;
264
276
  };
277
+ /**
278
+ * Type-only map from Groq chat model name to its supported provider tools.
279
+ * Groq exposes no provider-specific tool factories, so every model gets an
280
+ * empty tuple. This ensures that passing an Anthropic/OpenAI ProviderTool to
281
+ * a Groq adapter produces a compile-time type error.
282
+ */
283
+ export type GroqChatModelToolCapabilitiesByName = {
284
+ [LLAMA_3_1_8B_INSTANT.name]: typeof LLAMA_3_1_8B_INSTANT.supports.tools;
285
+ [LLAMA_3_3_70B_VERSATILE.name]: typeof LLAMA_3_3_70B_VERSATILE.supports.tools;
286
+ [LLAMA_4_MAVERICK_17B_128E_INSTRUCT.name]: typeof LLAMA_4_MAVERICK_17B_128E_INSTRUCT.supports.tools;
287
+ [LLAMA_4_SCOUT_17B_16E_INSTRUCT.name]: typeof LLAMA_4_SCOUT_17B_16E_INSTRUCT.supports.tools;
288
+ [LLAMA_GUARD_4_12B.name]: typeof LLAMA_GUARD_4_12B.supports.tools;
289
+ [LLAMA_PROMPT_GUARD_2_86M.name]: typeof LLAMA_PROMPT_GUARD_2_86M.supports.tools;
290
+ [LLAMA_PROMPT_GUARD_2_22M.name]: typeof LLAMA_PROMPT_GUARD_2_22M.supports.tools;
291
+ [GPT_OSS_20B.name]: typeof GPT_OSS_20B.supports.tools;
292
+ [GPT_OSS_120B.name]: typeof GPT_OSS_120B.supports.tools;
293
+ [GPT_OSS_SAFEGUARD_20B.name]: typeof GPT_OSS_SAFEGUARD_20B.supports.tools;
294
+ [KIMI_K2_INSTRUCT_0905.name]: typeof KIMI_K2_INSTRUCT_0905.supports.tools;
295
+ [QWEN3_32B.name]: typeof QWEN3_32B.supports.tools;
296
+ };
265
297
  /**
266
298
  * Resolves the provider options type for a specific Groq model.
267
299
  * Falls back to generic GroqTextProviderOptions for unknown models.
@@ -1 +1 @@
1
- {"version":3,"file":"model-meta.js","sources":["../../src/model-meta.ts"],"sourcesContent":["import type { GroqTextProviderOptions } from './text/text-provider-options'\n\n/**\n * Internal metadata structure describing a Groq model's capabilities and pricing.\n */\ninterface ModelMeta<TProviderOptions = unknown> {\n name: string\n context_window?: number\n max_completion_tokens?: number\n pricing: {\n input?: { normal: number; cached?: number }\n output?: { normal: number }\n }\n supports: {\n input: Array<'text' | 'image' | 'audio'>\n output: Array<'text' | 'audio'>\n endpoints: Array<'chat' | 'tts' | 'transcription' | 'batch'>\n\n features: Array<\n | 'streaming'\n | 'tools'\n | 'json_object'\n | 'browser_search'\n | 'code_execution'\n | 'reasoning'\n | 'content_moderation'\n | 'json_schema'\n | 'vision'\n >\n }\n /**\n * Type-level description of which provider options this model supports.\n */\n providerOptions?: TProviderOptions\n}\n\nconst LLAMA_3_3_70B_VERSATILE = {\n name: 'llama-3.3-70b-versatile',\n context_window: 131_072,\n max_completion_tokens: 32_768,\n pricing: {\n input: {\n normal: 0.59,\n },\n output: {\n normal: 0.79,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'tools', 'json_object'],\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst LLAMA_4_MAVERICK_17B_128E_INSTRUCT = {\n name: 'meta-llama/llama-4-maverick-17b-128e-instruct',\n context_window: 131_072,\n max_completion_tokens: 8_192,\n pricing: {\n input: {\n normal: 0.2,\n },\n output: {\n normal: 0.6,\n },\n },\n supports: {\n input: ['text', 'image'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'tools', 'json_object', 'json_schema', 'vision'],\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst LLAMA_4_SCOUT_17B_16E_INSTRUCT = {\n name: 'meta-llama/llama-4-scout-17b-16e-instruct',\n context_window: 131_072,\n max_completion_tokens: 8_192,\n pricing: {\n input: {\n normal: 0.05,\n },\n output: {\n normal: 0.08,\n },\n },\n supports: {\n input: ['text', 'image'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'tools', 'json_object'],\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst LLAMA_GUARD_4_12B = {\n name: 'meta-llama/llama-guard-4-12b',\n context_window: 131_072,\n max_completion_tokens: 1024,\n pricing: {\n input: {\n normal: 0.2,\n },\n output: {\n normal: 0.2,\n },\n },\n supports: {\n input: ['text', 'image'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'json_object', 'content_moderation', 'vision'],\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst LLAMA_PROMPT_GUARD_2_86M = {\n name: 'meta-llama/llama-prompt-guard-2-86m',\n context_window: 512,\n max_completion_tokens: 512,\n pricing: {\n input: {\n normal: 0.04,\n },\n output: {\n normal: 0.04,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'content_moderation', 'json_object'],\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst LLAMA_3_1_8B_INSTANT = {\n name: 'llama-3.1-8b-instant',\n context_window: 131_072,\n max_completion_tokens: 131_072,\n pricing: {\n input: {\n normal: 0.05,\n },\n output: {\n normal: 0.08,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'json_object', 'tools'],\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst LLAMA_PROMPT_GUARD_2_22M = {\n name: 'meta-llama/llama-prompt-guard-2-22m',\n context_window: 512,\n max_completion_tokens: 512,\n pricing: {\n input: {\n normal: 0.03,\n },\n output: {\n normal: 0.03,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'content_moderation'],\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst GPT_OSS_120B = {\n name: 'openai/gpt-oss-120b',\n context_window: 131_072,\n max_completion_tokens: 65_536,\n pricing: {\n input: {\n normal: 0.15,\n cached: 0.075,\n },\n output: {\n normal: 0.6,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: [\n 'streaming',\n 'json_object',\n 'json_schema',\n 'tools',\n 'browser_search',\n 'code_execution',\n 'reasoning',\n ],\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst GPT_OSS_SAFEGUARD_20B = {\n name: 'openai/gpt-oss-safeguard-20b',\n context_window: 131_072,\n max_completion_tokens: 65_536,\n pricing: {\n input: {\n normal: 0.075,\n cached: 0.037,\n },\n output: {\n normal: 0.3,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: [\n 'streaming',\n 'tools',\n 'browser_search',\n 'code_execution',\n 'json_object',\n 'json_schema',\n 'reasoning',\n 'content_moderation',\n ],\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst GPT_OSS_20B = {\n name: 'openai/gpt-oss-20b',\n context_window: 131_072,\n max_completion_tokens: 65_536,\n pricing: {\n input: {\n normal: 0.075,\n cached: 0.037,\n },\n output: {\n normal: 0.3,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: [\n 'streaming',\n 'browser_search',\n 'code_execution',\n 'json_object',\n 'json_schema',\n 'reasoning',\n 'tools',\n ],\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst KIMI_K2_INSTRUCT_0905 = {\n name: 'moonshotai/kimi-k2-instruct-0905',\n context_window: 262_144,\n max_completion_tokens: 16_384,\n pricing: {\n input: {\n normal: 1,\n cached: 0.5,\n },\n output: {\n normal: 3,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'tools', 'json_object', 'json_schema'],\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst QWEN3_32B = {\n name: 'qwen/qwen3-32b',\n context_window: 131_072,\n max_completion_tokens: 40_960,\n pricing: {\n input: {\n normal: 0.29,\n },\n output: {\n normal: 0.59,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'json_object', 'tools', 'reasoning'],\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\n/**\n * All supported Groq chat model identifiers.\n */\nexport const GROQ_CHAT_MODELS = [\n LLAMA_3_1_8B_INSTANT.name,\n LLAMA_3_3_70B_VERSATILE.name,\n LLAMA_4_MAVERICK_17B_128E_INSTRUCT.name,\n LLAMA_4_SCOUT_17B_16E_INSTRUCT.name,\n LLAMA_GUARD_4_12B.name,\n LLAMA_PROMPT_GUARD_2_86M.name,\n LLAMA_PROMPT_GUARD_2_22M.name,\n GPT_OSS_20B.name,\n GPT_OSS_120B.name,\n GPT_OSS_SAFEGUARD_20B.name,\n KIMI_K2_INSTRUCT_0905.name,\n QWEN3_32B.name,\n] as const\n\n/**\n * Union type of all supported Groq chat model names.\n */\nexport type GroqChatModels = (typeof GROQ_CHAT_MODELS)[number]\n\n/**\n * Type-only map from Groq chat model name to its supported input modalities.\n */\nexport type GroqModelInputModalitiesByName = {\n [LLAMA_3_1_8B_INSTANT.name]: typeof LLAMA_3_1_8B_INSTANT.supports.input\n [LLAMA_3_3_70B_VERSATILE.name]: typeof LLAMA_3_3_70B_VERSATILE.supports.input\n [LLAMA_4_MAVERICK_17B_128E_INSTRUCT.name]: typeof LLAMA_4_MAVERICK_17B_128E_INSTRUCT.supports.input\n [LLAMA_4_SCOUT_17B_16E_INSTRUCT.name]: typeof LLAMA_4_SCOUT_17B_16E_INSTRUCT.supports.input\n [LLAMA_GUARD_4_12B.name]: typeof LLAMA_GUARD_4_12B.supports.input\n [LLAMA_PROMPT_GUARD_2_86M.name]: typeof LLAMA_PROMPT_GUARD_2_86M.supports.input\n [LLAMA_PROMPT_GUARD_2_22M.name]: typeof LLAMA_PROMPT_GUARD_2_22M.supports.input\n [GPT_OSS_20B.name]: typeof GPT_OSS_20B.supports.input\n [GPT_OSS_120B.name]: typeof GPT_OSS_120B.supports.input\n [GPT_OSS_SAFEGUARD_20B.name]: typeof GPT_OSS_SAFEGUARD_20B.supports.input\n [KIMI_K2_INSTRUCT_0905.name]: typeof KIMI_K2_INSTRUCT_0905.supports.input\n [QWEN3_32B.name]: typeof QWEN3_32B.supports.input\n}\n\n/**\n * Type-only map from Groq chat model name to its provider options type.\n */\nexport type GroqChatModelProviderOptionsByName = {\n [K in (typeof GROQ_CHAT_MODELS)[number]]: GroqTextProviderOptions\n}\n\n/**\n * Resolves the provider options type for a specific Groq model.\n * Falls back to generic GroqTextProviderOptions for unknown models.\n */\nexport type ResolveProviderOptions<TModel extends string> =\n TModel extends keyof GroqChatModelProviderOptionsByName\n ? GroqChatModelProviderOptionsByName[TModel]\n : GroqTextProviderOptions\n\n/**\n * Resolve input modalities for a specific model.\n * If the model has explicit modalities in the map, use those; otherwise use text only.\n */\nexport type ResolveInputModalities<TModel extends string> =\n TModel extends keyof GroqModelInputModalitiesByName\n ? GroqModelInputModalitiesByName[TModel]\n : readonly ['text']\n"],"names":[],"mappings":"AAoCA,MAAM,0BAA0B;AAAA,EAC9B,MAAM;AAiBR;AAEA,MAAM,qCAAqC;AAAA,EACzC,MAAM;AAiBR;AAEA,MAAM,iCAAiC;AAAA,EACrC,MAAM;AAiBR;AAEA,MAAM,oBAAoB;AAAA,EACxB,MAAM;AAiBR;AAEA,MAAM,2BAA2B;AAAA,EAC/B,MAAM;AAiBR;AAEA,MAAM,uBAAuB;AAAA,EAC3B,MAAM;AAiBR;AAEA,MAAM,2BAA2B;AAAA,EAC/B,MAAM;AAiBR;AAEA,MAAM,eAAe;AAAA,EACnB,MAAM;AA0BR;AAEA,MAAM,wBAAwB;AAAA,EAC5B,MAAM;AA2BR;AAEA,MAAM,cAAc;AAAA,EAClB,MAAM;AA0BR;AAEA,MAAM,wBAAwB;AAAA,EAC5B,MAAM;AAkBR;AAEA,MAAM,YAAY;AAAA,EAChB,MAAM;AAiBR;AAKO,MAAM,mBAAmB;AAAA,EAC9B,qBAAqB;AAAA,EACrB,wBAAwB;AAAA,EACxB,mCAAmC;AAAA,EACnC,+BAA+B;AAAA,EAC/B,kBAAkB;AAAA,EAClB,yBAAyB;AAAA,EACzB,yBAAyB;AAAA,EACzB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,sBAAsB;AAAA,EACtB,sBAAsB;AAAA,EACtB,UAAU;AACZ;"}
1
+ {"version":3,"file":"model-meta.js","sources":["../../src/model-meta.ts"],"sourcesContent":["import type { GroqTextProviderOptions } from './text/text-provider-options'\n\n/**\n * Internal metadata structure describing a Groq model's capabilities and pricing.\n */\ninterface ModelMeta<TProviderOptions = unknown> {\n name: string\n context_window?: number\n max_completion_tokens?: number\n pricing: {\n input?: { normal: number; cached?: number }\n output?: { normal: number }\n }\n supports: {\n input: Array<'text' | 'image' | 'audio'>\n output: Array<'text' | 'audio'>\n endpoints: Array<'chat' | 'tts' | 'transcription' | 'batch'>\n\n features: Array<\n | 'streaming'\n | 'tools'\n | 'json_object'\n | 'browser_search'\n | 'code_execution'\n | 'reasoning'\n | 'content_moderation'\n | 'json_schema'\n | 'vision'\n >\n tools?: ReadonlyArray<never>\n }\n /**\n * Type-level description of which provider options this model supports.\n */\n providerOptions?: TProviderOptions\n}\n\nconst LLAMA_3_3_70B_VERSATILE = {\n name: 'llama-3.3-70b-versatile',\n context_window: 131_072,\n max_completion_tokens: 32_768,\n pricing: {\n input: {\n normal: 0.59,\n },\n output: {\n normal: 0.79,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'tools', 'json_object'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst LLAMA_4_MAVERICK_17B_128E_INSTRUCT = {\n name: 'meta-llama/llama-4-maverick-17b-128e-instruct',\n context_window: 131_072,\n max_completion_tokens: 8_192,\n pricing: {\n input: {\n normal: 0.2,\n },\n output: {\n normal: 0.6,\n },\n },\n supports: {\n input: ['text', 'image'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'tools', 'json_object', 'json_schema', 'vision'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst LLAMA_4_SCOUT_17B_16E_INSTRUCT = {\n name: 'meta-llama/llama-4-scout-17b-16e-instruct',\n context_window: 131_072,\n max_completion_tokens: 8_192,\n pricing: {\n input: {\n normal: 0.05,\n },\n output: {\n normal: 0.08,\n },\n },\n supports: {\n input: ['text', 'image'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'tools', 'json_object'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst LLAMA_GUARD_4_12B = {\n name: 'meta-llama/llama-guard-4-12b',\n context_window: 131_072,\n max_completion_tokens: 1024,\n pricing: {\n input: {\n normal: 0.2,\n },\n output: {\n normal: 0.2,\n },\n },\n supports: {\n input: ['text', 'image'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'json_object', 'content_moderation', 'vision'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst LLAMA_PROMPT_GUARD_2_86M = {\n name: 'meta-llama/llama-prompt-guard-2-86m',\n context_window: 512,\n max_completion_tokens: 512,\n pricing: {\n input: {\n normal: 0.04,\n },\n output: {\n normal: 0.04,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'content_moderation', 'json_object'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst LLAMA_3_1_8B_INSTANT = {\n name: 'llama-3.1-8b-instant',\n context_window: 131_072,\n max_completion_tokens: 131_072,\n pricing: {\n input: {\n normal: 0.05,\n },\n output: {\n normal: 0.08,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'json_object', 'tools'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst LLAMA_PROMPT_GUARD_2_22M = {\n name: 'meta-llama/llama-prompt-guard-2-22m',\n context_window: 512,\n max_completion_tokens: 512,\n pricing: {\n input: {\n normal: 0.03,\n },\n output: {\n normal: 0.03,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'content_moderation'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst GPT_OSS_120B = {\n name: 'openai/gpt-oss-120b',\n context_window: 131_072,\n max_completion_tokens: 65_536,\n pricing: {\n input: {\n normal: 0.15,\n cached: 0.075,\n },\n output: {\n normal: 0.6,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: [\n 'streaming',\n 'json_object',\n 'json_schema',\n 'tools',\n 'browser_search',\n 'code_execution',\n 'reasoning',\n ],\n tools: [] as const,\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst GPT_OSS_SAFEGUARD_20B = {\n name: 'openai/gpt-oss-safeguard-20b',\n context_window: 131_072,\n max_completion_tokens: 65_536,\n pricing: {\n input: {\n normal: 0.075,\n cached: 0.037,\n },\n output: {\n normal: 0.3,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: [\n 'streaming',\n 'tools',\n 'browser_search',\n 'code_execution',\n 'json_object',\n 'json_schema',\n 'reasoning',\n 'content_moderation',\n ],\n tools: [] as const,\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst GPT_OSS_20B = {\n name: 'openai/gpt-oss-20b',\n context_window: 131_072,\n max_completion_tokens: 65_536,\n pricing: {\n input: {\n normal: 0.075,\n cached: 0.037,\n },\n output: {\n normal: 0.3,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: [\n 'streaming',\n 'browser_search',\n 'code_execution',\n 'json_object',\n 'json_schema',\n 'reasoning',\n 'tools',\n ],\n tools: [] as const,\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst KIMI_K2_INSTRUCT_0905 = {\n name: 'moonshotai/kimi-k2-instruct-0905',\n context_window: 262_144,\n max_completion_tokens: 16_384,\n pricing: {\n input: {\n normal: 1,\n cached: 0.5,\n },\n output: {\n normal: 3,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'tools', 'json_object', 'json_schema'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\nconst QWEN3_32B = {\n name: 'qwen/qwen3-32b',\n context_window: 131_072,\n max_completion_tokens: 40_960,\n pricing: {\n input: {\n normal: 0.29,\n },\n output: {\n normal: 0.59,\n },\n },\n supports: {\n input: ['text'],\n output: ['text'],\n endpoints: ['chat'],\n features: ['streaming', 'json_object', 'tools', 'reasoning'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta<GroqTextProviderOptions>\n\n/**\n * All supported Groq chat model identifiers.\n */\nexport const GROQ_CHAT_MODELS = [\n LLAMA_3_1_8B_INSTANT.name,\n LLAMA_3_3_70B_VERSATILE.name,\n LLAMA_4_MAVERICK_17B_128E_INSTRUCT.name,\n LLAMA_4_SCOUT_17B_16E_INSTRUCT.name,\n LLAMA_GUARD_4_12B.name,\n LLAMA_PROMPT_GUARD_2_86M.name,\n LLAMA_PROMPT_GUARD_2_22M.name,\n GPT_OSS_20B.name,\n GPT_OSS_120B.name,\n GPT_OSS_SAFEGUARD_20B.name,\n KIMI_K2_INSTRUCT_0905.name,\n QWEN3_32B.name,\n] as const\n\n/**\n * Union type of all supported Groq chat model names.\n */\nexport type GroqChatModels = (typeof GROQ_CHAT_MODELS)[number]\n\n/**\n * Type-only map from Groq chat model name to its supported input modalities.\n */\nexport type GroqModelInputModalitiesByName = {\n [LLAMA_3_1_8B_INSTANT.name]: typeof LLAMA_3_1_8B_INSTANT.supports.input\n [LLAMA_3_3_70B_VERSATILE.name]: typeof LLAMA_3_3_70B_VERSATILE.supports.input\n [LLAMA_4_MAVERICK_17B_128E_INSTRUCT.name]: typeof LLAMA_4_MAVERICK_17B_128E_INSTRUCT.supports.input\n [LLAMA_4_SCOUT_17B_16E_INSTRUCT.name]: typeof LLAMA_4_SCOUT_17B_16E_INSTRUCT.supports.input\n [LLAMA_GUARD_4_12B.name]: typeof LLAMA_GUARD_4_12B.supports.input\n [LLAMA_PROMPT_GUARD_2_86M.name]: typeof LLAMA_PROMPT_GUARD_2_86M.supports.input\n [LLAMA_PROMPT_GUARD_2_22M.name]: typeof LLAMA_PROMPT_GUARD_2_22M.supports.input\n [GPT_OSS_20B.name]: typeof GPT_OSS_20B.supports.input\n [GPT_OSS_120B.name]: typeof GPT_OSS_120B.supports.input\n [GPT_OSS_SAFEGUARD_20B.name]: typeof GPT_OSS_SAFEGUARD_20B.supports.input\n [KIMI_K2_INSTRUCT_0905.name]: typeof KIMI_K2_INSTRUCT_0905.supports.input\n [QWEN3_32B.name]: typeof QWEN3_32B.supports.input\n}\n\n/**\n * Type-only map from Groq chat model name to its provider options type.\n */\nexport type GroqChatModelProviderOptionsByName = {\n [K in (typeof GROQ_CHAT_MODELS)[number]]: GroqTextProviderOptions\n}\n\n/**\n * Type-only map from Groq chat model name to its supported provider tools.\n * Groq exposes no provider-specific tool factories, so every model gets an\n * empty tuple. This ensures that passing an Anthropic/OpenAI ProviderTool to\n * a Groq adapter produces a compile-time type error.\n */\nexport type GroqChatModelToolCapabilitiesByName = {\n [LLAMA_3_1_8B_INSTANT.name]: typeof LLAMA_3_1_8B_INSTANT.supports.tools\n [LLAMA_3_3_70B_VERSATILE.name]: typeof LLAMA_3_3_70B_VERSATILE.supports.tools\n [LLAMA_4_MAVERICK_17B_128E_INSTRUCT.name]: typeof LLAMA_4_MAVERICK_17B_128E_INSTRUCT.supports.tools\n [LLAMA_4_SCOUT_17B_16E_INSTRUCT.name]: typeof LLAMA_4_SCOUT_17B_16E_INSTRUCT.supports.tools\n [LLAMA_GUARD_4_12B.name]: typeof LLAMA_GUARD_4_12B.supports.tools\n [LLAMA_PROMPT_GUARD_2_86M.name]: typeof LLAMA_PROMPT_GUARD_2_86M.supports.tools\n [LLAMA_PROMPT_GUARD_2_22M.name]: typeof LLAMA_PROMPT_GUARD_2_22M.supports.tools\n [GPT_OSS_20B.name]: typeof GPT_OSS_20B.supports.tools\n [GPT_OSS_120B.name]: typeof GPT_OSS_120B.supports.tools\n [GPT_OSS_SAFEGUARD_20B.name]: typeof GPT_OSS_SAFEGUARD_20B.supports.tools\n [KIMI_K2_INSTRUCT_0905.name]: typeof KIMI_K2_INSTRUCT_0905.supports.tools\n [QWEN3_32B.name]: typeof QWEN3_32B.supports.tools\n}\n\n/**\n * Resolves the provider options type for a specific Groq model.\n * Falls back to generic GroqTextProviderOptions for unknown models.\n */\nexport type ResolveProviderOptions<TModel extends string> =\n TModel extends keyof GroqChatModelProviderOptionsByName\n ? GroqChatModelProviderOptionsByName[TModel]\n : GroqTextProviderOptions\n\n/**\n * Resolve input modalities for a specific model.\n * If the model has explicit modalities in the map, use those; otherwise use text only.\n */\nexport type ResolveInputModalities<TModel extends string> =\n TModel extends keyof GroqModelInputModalitiesByName\n ? GroqModelInputModalitiesByName[TModel]\n : readonly ['text']\n"],"names":[],"mappings":"AAqCA,MAAM,0BAA0B;AAAA,EAC9B,MAAM;AAkBR;AAEA,MAAM,qCAAqC;AAAA,EACzC,MAAM;AAkBR;AAEA,MAAM,iCAAiC;AAAA,EACrC,MAAM;AAkBR;AAEA,MAAM,oBAAoB;AAAA,EACxB,MAAM;AAkBR;AAEA,MAAM,2BAA2B;AAAA,EAC/B,MAAM;AAkBR;AAEA,MAAM,uBAAuB;AAAA,EAC3B,MAAM;AAkBR;AAEA,MAAM,2BAA2B;AAAA,EAC/B,MAAM;AAkBR;AAEA,MAAM,eAAe;AAAA,EACnB,MAAM;AA2BR;AAEA,MAAM,wBAAwB;AAAA,EAC5B,MAAM;AA4BR;AAEA,MAAM,cAAc;AAAA,EAClB,MAAM;AA2BR;AAEA,MAAM,wBAAwB;AAAA,EAC5B,MAAM;AAmBR;AAEA,MAAM,YAAY;AAAA,EAChB,MAAM;AAkBR;AAKO,MAAM,mBAAmB;AAAA,EAC9B,qBAAqB;AAAA,EACrB,wBAAwB;AAAA,EACxB,mCAAmC;AAAA,EACnC,+BAA+B;AAAA,EAC/B,kBAAkB;AAAA,EAClB,yBAAyB;AAAA,EACzB,yBAAyB;AAAA,EACzB,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,sBAAsB;AAAA,EACtB,sBAAsB;AAAA,EACtB,UAAU;AACZ;"}
@@ -0,0 +1,7 @@
1
+ import { convertFunctionToolToAdapterFormat } from "./function-tool.js";
2
+ import { convertToolsToProviderFormat } from "./tool-converter.js";
3
+ export {
4
+ convertFunctionToolToAdapterFormat,
5
+ convertToolsToProviderFormat
6
+ };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/ai-groq",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "description": "Groq adapter for TanStack AI",
6
6
  "author": "",
@@ -16,6 +16,10 @@
16
16
  ".": {
17
17
  "types": "./dist/esm/index.d.ts",
18
18
  "import": "./dist/esm/index.js"
19
+ },
20
+ "./tools": {
21
+ "types": "./dist/esm/tools/index.d.ts",
22
+ "import": "./dist/esm/tools/index.js"
19
23
  }
20
24
  },
21
25
  "files": [
@@ -34,7 +38,7 @@
34
38
  },
35
39
  "peerDependencies": {
36
40
  "zod": "^4.0.0",
37
- "@tanstack/ai": "^0.10.0"
41
+ "@tanstack/ai": "^0.12.0"
38
42
  },
39
43
  "dependencies": {
40
44
  "groq-sdk": "^0.37.0"
@@ -10,6 +10,7 @@ import {
10
10
  } from '../utils'
11
11
  import type {
12
12
  GROQ_CHAT_MODELS,
13
+ GroqChatModelToolCapabilitiesByName,
13
14
  ResolveInputModalities,
14
15
  ResolveProviderOptions,
15
16
  } from '../model-meta'
@@ -21,11 +22,15 @@ import type GROQ_SDK from 'groq-sdk'
21
22
  import type { ChatCompletionCreateParamsStreaming } from 'groq-sdk/resources/chat/completions'
22
23
  import type {
23
24
  ContentPart,
25
+ Modality,
24
26
  ModelMessage,
25
27
  StreamChunk,
26
28
  TextOptions,
27
29
  } from '@tanstack/ai'
28
- import type { InternalTextProviderOptions } from '../text/text-provider-options'
30
+ import type {
31
+ ExternalTextProviderOptions,
32
+ InternalTextProviderOptions,
33
+ } from '../text/text-provider-options'
29
34
  import type {
30
35
  ChatCompletionContentPart,
31
36
  ChatCompletionMessageParam,
@@ -34,6 +39,18 @@ import type {
34
39
  } from '../message-types'
35
40
  import type { GroqClientConfig } from '../utils'
36
41
 
42
+ type GroqTextProviderOptions = ExternalTextProviderOptions
43
+
44
+ type ResolveToolCapabilities<TModel extends string> =
45
+ TModel extends keyof GroqChatModelToolCapabilitiesByName
46
+ ? NonNullable<GroqChatModelToolCapabilitiesByName[TModel]>
47
+ : readonly []
48
+
49
+ /** Cast an event object to StreamChunk. Adapters construct events with string
50
+ * literal types which are structurally compatible with the EventType enum. */
51
+ const asChunk = (chunk: Record<string, unknown>) =>
52
+ chunk as unknown as StreamChunk
53
+
37
54
  /**
38
55
  * Configuration for Groq text adapter
39
56
  */
@@ -52,11 +69,17 @@ export type { ExternalTextProviderOptions as GroqTextProviderOptions } from '../
52
69
  */
53
70
  export class GroqTextAdapter<
54
71
  TModel extends (typeof GROQ_CHAT_MODELS)[number],
72
+ TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>,
73
+ TInputModalities extends ReadonlyArray<Modality> =
74
+ ResolveInputModalities<TModel>,
75
+ TToolCapabilities extends ReadonlyArray<string> =
76
+ ResolveToolCapabilities<TModel>,
55
77
  > extends BaseTextAdapter<
56
78
  TModel,
57
- ResolveProviderOptions<TModel>,
58
- ResolveInputModalities<TModel>,
59
- GroqMessageMetadataByModality
79
+ TProviderOptions,
80
+ TInputModalities,
81
+ GroqMessageMetadataByModality,
82
+ TToolCapabilities
60
83
  > {
61
84
  readonly kind = 'text' as const
62
85
  readonly name = 'groq' as const
@@ -69,13 +92,14 @@ export class GroqTextAdapter<
69
92
  }
70
93
 
71
94
  async *chatStream(
72
- options: TextOptions<ResolveProviderOptions<TModel>>,
95
+ options: TextOptions<GroqTextProviderOptions>,
73
96
  ): AsyncIterable<StreamChunk> {
74
97
  const requestParams = this.mapTextOptionsToGroq(options)
75
98
  const timestamp = Date.now()
76
99
 
77
100
  const aguiState = {
78
- runId: generateId(this.name),
101
+ runId: options.runId ?? generateId(this.name),
102
+ threadId: options.threadId ?? generateId(this.name),
79
103
  messageId: generateId(this.name),
80
104
  timestamp,
81
105
  hasEmittedRunStarted: false,
@@ -93,24 +117,27 @@ export class GroqTextAdapter<
93
117
 
94
118
  if (!aguiState.hasEmittedRunStarted) {
95
119
  aguiState.hasEmittedRunStarted = true
96
- yield {
120
+ yield asChunk({
97
121
  type: 'RUN_STARTED',
98
122
  runId: aguiState.runId,
123
+ threadId: aguiState.threadId,
99
124
  model: options.model,
100
125
  timestamp,
101
- }
126
+ })
102
127
  }
103
128
 
104
- yield {
129
+ yield asChunk({
105
130
  type: 'RUN_ERROR',
106
131
  runId: aguiState.runId,
107
132
  model: options.model,
108
133
  timestamp,
134
+ message: err.message || 'Unknown error',
135
+ code: err.code,
109
136
  error: {
110
137
  message: err.message || 'Unknown error',
111
138
  code: err.code,
112
139
  },
113
- }
140
+ })
114
141
 
115
142
  console.error('>>> chatStream: Fatal error during response creation <<<')
116
143
  console.error('>>> Error message:', err.message)
@@ -132,7 +159,7 @@ export class GroqTextAdapter<
132
159
  * We apply Groq-specific transformations for structured output compatibility.
133
160
  */
134
161
  async structuredOutput(
135
- options: StructuredOutputOptions<ResolveProviderOptions<TModel>>,
162
+ options: StructuredOutputOptions<GroqTextProviderOptions>,
136
163
  ): Promise<StructuredOutputResult<unknown>> {
137
164
  const { chatOptions, outputSchema } = options
138
165
  const requestParams = this.mapTextOptionsToGroq(chatOptions)
@@ -190,6 +217,7 @@ export class GroqTextAdapter<
190
217
  options: TextOptions,
191
218
  aguiState: {
192
219
  runId: string
220
+ threadId: string
193
221
  messageId: string
194
222
  timestamp: number
195
223
  hasEmittedRunStarted: boolean
@@ -217,12 +245,13 @@ export class GroqTextAdapter<
217
245
 
218
246
  if (!aguiState.hasEmittedRunStarted) {
219
247
  aguiState.hasEmittedRunStarted = true
220
- yield {
248
+ yield asChunk({
221
249
  type: 'RUN_STARTED',
222
250
  runId: aguiState.runId,
251
+ threadId: aguiState.threadId,
223
252
  model: chunk.model || options.model,
224
253
  timestamp,
225
- }
254
+ })
226
255
  }
227
256
 
228
257
  const delta = choice.delta
@@ -232,25 +261,25 @@ export class GroqTextAdapter<
232
261
  if (deltaContent) {
233
262
  if (!hasEmittedTextMessageStart) {
234
263
  hasEmittedTextMessageStart = true
235
- yield {
264
+ yield asChunk({
236
265
  type: 'TEXT_MESSAGE_START',
237
266
  messageId: aguiState.messageId,
238
267
  model: chunk.model || options.model,
239
268
  timestamp,
240
269
  role: 'assistant',
241
- }
270
+ })
242
271
  }
243
272
 
244
273
  accumulatedContent += deltaContent
245
274
 
246
- yield {
275
+ yield asChunk({
247
276
  type: 'TEXT_MESSAGE_CONTENT',
248
277
  messageId: aguiState.messageId,
249
278
  model: chunk.model || options.model,
250
279
  timestamp,
251
280
  delta: deltaContent,
252
281
  content: accumulatedContent,
253
- }
282
+ })
254
283
  }
255
284
 
256
285
  if (deltaToolCalls) {
@@ -280,24 +309,25 @@ export class GroqTextAdapter<
280
309
 
281
310
  if (toolCall.id && toolCall.name && !toolCall.started) {
282
311
  toolCall.started = true
283
- yield {
312
+ yield asChunk({
284
313
  type: 'TOOL_CALL_START',
285
314
  toolCallId: toolCall.id,
315
+ toolCallName: toolCall.name,
286
316
  toolName: toolCall.name,
287
317
  model: chunk.model || options.model,
288
318
  timestamp,
289
319
  index,
290
- }
320
+ })
291
321
  }
292
322
 
293
323
  if (toolCallDelta.function?.arguments && toolCall.started) {
294
- yield {
324
+ yield asChunk({
295
325
  type: 'TOOL_CALL_ARGS',
296
326
  toolCallId: toolCall.id,
297
327
  model: chunk.model || options.model,
298
328
  timestamp,
299
329
  delta: toolCallDelta.function.arguments,
300
- }
330
+ })
301
331
  }
302
332
  }
303
333
  }
@@ -321,14 +351,15 @@ export class GroqTextAdapter<
321
351
  parsedInput = {}
322
352
  }
323
353
 
324
- yield {
354
+ yield asChunk({
325
355
  type: 'TOOL_CALL_END',
326
356
  toolCallId: toolCall.id,
357
+ toolCallName: toolCall.name,
327
358
  toolName: toolCall.name,
328
359
  model: chunk.model || options.model,
329
360
  timestamp,
330
361
  input: parsedInput,
331
- }
362
+ })
332
363
  }
333
364
  }
334
365
 
@@ -341,19 +372,20 @@ export class GroqTextAdapter<
341
372
  : 'stop'
342
373
 
343
374
  if (hasEmittedTextMessageStart) {
344
- yield {
375
+ yield asChunk({
345
376
  type: 'TEXT_MESSAGE_END',
346
377
  messageId: aguiState.messageId,
347
378
  model: chunk.model || options.model,
348
379
  timestamp,
349
- }
380
+ })
350
381
  }
351
382
 
352
383
  const groqUsage = chunk.x_groq?.usage
353
384
 
354
- yield {
385
+ yield asChunk({
355
386
  type: 'RUN_FINISHED',
356
387
  runId: aguiState.runId,
388
+ threadId: aguiState.threadId,
357
389
  model: chunk.model || options.model,
358
390
  timestamp,
359
391
  usage: groqUsage
@@ -364,23 +396,25 @@ export class GroqTextAdapter<
364
396
  }
365
397
  : undefined,
366
398
  finishReason: computedFinishReason,
367
- }
399
+ })
368
400
  }
369
401
  }
370
402
  } catch (error: unknown) {
371
403
  const err = error as Error & { code?: string }
372
404
  console.log('[Groq Adapter] Stream ended with error:', err.message)
373
405
 
374
- yield {
406
+ yield asChunk({
375
407
  type: 'RUN_ERROR',
376
408
  runId: aguiState.runId,
377
409
  model: options.model,
378
410
  timestamp,
411
+ message: err.message || 'Unknown error occurred',
412
+ code: err.code,
379
413
  error: {
380
414
  message: err.message || 'Unknown error occurred',
381
415
  code: err.code,
382
416
  },
383
- }
417
+ })
384
418
  }
385
419
  }
386
420
 
package/src/index.ts CHANGED
@@ -17,6 +17,7 @@ export {
17
17
  // Types
18
18
  export type {
19
19
  GroqChatModelProviderOptionsByName,
20
+ GroqChatModelToolCapabilitiesByName,
20
21
  GroqModelInputModalitiesByName,
21
22
  ResolveProviderOptions,
22
23
  ResolveInputModalities,
package/src/model-meta.ts CHANGED
@@ -27,6 +27,7 @@ interface ModelMeta<TProviderOptions = unknown> {
27
27
  | 'json_schema'
28
28
  | 'vision'
29
29
  >
30
+ tools?: ReadonlyArray<never>
30
31
  }
31
32
  /**
32
33
  * Type-level description of which provider options this model supports.
@@ -51,6 +52,7 @@ const LLAMA_3_3_70B_VERSATILE = {
51
52
  output: ['text'],
52
53
  endpoints: ['chat'],
53
54
  features: ['streaming', 'tools', 'json_object'],
55
+ tools: [] as const,
54
56
  },
55
57
  } as const satisfies ModelMeta<GroqTextProviderOptions>
56
58
 
@@ -71,6 +73,7 @@ const LLAMA_4_MAVERICK_17B_128E_INSTRUCT = {
71
73
  output: ['text'],
72
74
  endpoints: ['chat'],
73
75
  features: ['streaming', 'tools', 'json_object', 'json_schema', 'vision'],
76
+ tools: [] as const,
74
77
  },
75
78
  } as const satisfies ModelMeta<GroqTextProviderOptions>
76
79
 
@@ -91,6 +94,7 @@ const LLAMA_4_SCOUT_17B_16E_INSTRUCT = {
91
94
  output: ['text'],
92
95
  endpoints: ['chat'],
93
96
  features: ['streaming', 'tools', 'json_object'],
97
+ tools: [] as const,
94
98
  },
95
99
  } as const satisfies ModelMeta<GroqTextProviderOptions>
96
100
 
@@ -111,6 +115,7 @@ const LLAMA_GUARD_4_12B = {
111
115
  output: ['text'],
112
116
  endpoints: ['chat'],
113
117
  features: ['streaming', 'json_object', 'content_moderation', 'vision'],
118
+ tools: [] as const,
114
119
  },
115
120
  } as const satisfies ModelMeta<GroqTextProviderOptions>
116
121
 
@@ -131,6 +136,7 @@ const LLAMA_PROMPT_GUARD_2_86M = {
131
136
  output: ['text'],
132
137
  endpoints: ['chat'],
133
138
  features: ['streaming', 'content_moderation', 'json_object'],
139
+ tools: [] as const,
134
140
  },
135
141
  } as const satisfies ModelMeta<GroqTextProviderOptions>
136
142
 
@@ -151,6 +157,7 @@ const LLAMA_3_1_8B_INSTANT = {
151
157
  output: ['text'],
152
158
  endpoints: ['chat'],
153
159
  features: ['streaming', 'json_object', 'tools'],
160
+ tools: [] as const,
154
161
  },
155
162
  } as const satisfies ModelMeta<GroqTextProviderOptions>
156
163
 
@@ -171,6 +178,7 @@ const LLAMA_PROMPT_GUARD_2_22M = {
171
178
  output: ['text'],
172
179
  endpoints: ['chat'],
173
180
  features: ['streaming', 'content_moderation'],
181
+ tools: [] as const,
174
182
  },
175
183
  } as const satisfies ModelMeta<GroqTextProviderOptions>
176
184
 
@@ -200,6 +208,7 @@ const GPT_OSS_120B = {
200
208
  'code_execution',
201
209
  'reasoning',
202
210
  ],
211
+ tools: [] as const,
203
212
  },
204
213
  } as const satisfies ModelMeta<GroqTextProviderOptions>
205
214
 
@@ -230,6 +239,7 @@ const GPT_OSS_SAFEGUARD_20B = {
230
239
  'reasoning',
231
240
  'content_moderation',
232
241
  ],
242
+ tools: [] as const,
233
243
  },
234
244
  } as const satisfies ModelMeta<GroqTextProviderOptions>
235
245
 
@@ -259,6 +269,7 @@ const GPT_OSS_20B = {
259
269
  'reasoning',
260
270
  'tools',
261
271
  ],
272
+ tools: [] as const,
262
273
  },
263
274
  } as const satisfies ModelMeta<GroqTextProviderOptions>
264
275
 
@@ -280,6 +291,7 @@ const KIMI_K2_INSTRUCT_0905 = {
280
291
  output: ['text'],
281
292
  endpoints: ['chat'],
282
293
  features: ['streaming', 'tools', 'json_object', 'json_schema'],
294
+ tools: [] as const,
283
295
  },
284
296
  } as const satisfies ModelMeta<GroqTextProviderOptions>
285
297
 
@@ -300,6 +312,7 @@ const QWEN3_32B = {
300
312
  output: ['text'],
301
313
  endpoints: ['chat'],
302
314
  features: ['streaming', 'json_object', 'tools', 'reasoning'],
315
+ tools: [] as const,
303
316
  },
304
317
  } as const satisfies ModelMeta<GroqTextProviderOptions>
305
318
 
@@ -351,6 +364,27 @@ export type GroqChatModelProviderOptionsByName = {
351
364
  [K in (typeof GROQ_CHAT_MODELS)[number]]: GroqTextProviderOptions
352
365
  }
353
366
 
367
+ /**
368
+ * Type-only map from Groq chat model name to its supported provider tools.
369
+ * Groq exposes no provider-specific tool factories, so every model gets an
370
+ * empty tuple. This ensures that passing an Anthropic/OpenAI ProviderTool to
371
+ * a Groq adapter produces a compile-time type error.
372
+ */
373
+ export type GroqChatModelToolCapabilitiesByName = {
374
+ [LLAMA_3_1_8B_INSTANT.name]: typeof LLAMA_3_1_8B_INSTANT.supports.tools
375
+ [LLAMA_3_3_70B_VERSATILE.name]: typeof LLAMA_3_3_70B_VERSATILE.supports.tools
376
+ [LLAMA_4_MAVERICK_17B_128E_INSTRUCT.name]: typeof LLAMA_4_MAVERICK_17B_128E_INSTRUCT.supports.tools
377
+ [LLAMA_4_SCOUT_17B_16E_INSTRUCT.name]: typeof LLAMA_4_SCOUT_17B_16E_INSTRUCT.supports.tools
378
+ [LLAMA_GUARD_4_12B.name]: typeof LLAMA_GUARD_4_12B.supports.tools
379
+ [LLAMA_PROMPT_GUARD_2_86M.name]: typeof LLAMA_PROMPT_GUARD_2_86M.supports.tools
380
+ [LLAMA_PROMPT_GUARD_2_22M.name]: typeof LLAMA_PROMPT_GUARD_2_22M.supports.tools
381
+ [GPT_OSS_20B.name]: typeof GPT_OSS_20B.supports.tools
382
+ [GPT_OSS_120B.name]: typeof GPT_OSS_120B.supports.tools
383
+ [GPT_OSS_SAFEGUARD_20B.name]: typeof GPT_OSS_SAFEGUARD_20B.supports.tools
384
+ [KIMI_K2_INSTRUCT_0905.name]: typeof KIMI_K2_INSTRUCT_0905.supports.tools
385
+ [QWEN3_32B.name]: typeof QWEN3_32B.supports.tools
386
+ }
387
+
354
388
  /**
355
389
  * Resolves the provider options type for a specific Groq model.
356
390
  * Falls back to generic GroqTextProviderOptions for unknown models.