@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,179 @@
1
+ import { ChatCompletionMessageParam, ChatCompletionTool, ChatCompletionToolChoiceOption, CompoundCustom, Document, ResponseFormatJsonObject, ResponseFormatJsonSchema, ResponseFormatText, SearchSettings } from '../message-types.js';
2
+ /**
3
+ * Groq-specific provider options for text/chat models.
4
+ *
5
+ * These options extend the standard Chat Completions API parameters
6
+ * with Groq-specific features like compound models and search settings.
7
+ *
8
+ * @see https://console.groq.com/docs/api-reference#chat
9
+ */
10
+ export interface GroqTextProviderOptions {
11
+ /**
12
+ * Whether to enable citations in the response. When enabled, the model will
13
+ * include citations for information retrieved from provided documents or web
14
+ * searches.
15
+ */
16
+ citation_options?: 'enabled' | 'disabled' | null;
17
+ /** Custom configuration of models and tools for Compound. */
18
+ compound_custom?: CompoundCustom | null;
19
+ /**
20
+ * If set to true, groq will return called tools without validating that the tool
21
+ * is present in request.tools. tool_choice=required/none will still be enforced,
22
+ * but the request cannot require a specific tool be used.
23
+ */
24
+ disable_tool_validation?: boolean;
25
+ /**
26
+ * A list of documents to provide context for the conversation. Each document
27
+ * contains text that can be referenced by the model.
28
+ */
29
+ documents?: Array<Document> | null;
30
+ /**
31
+ * Number between -2.0 and 2.0. Positive values penalize new tokens based on their
32
+ * existing frequency in the text so far, decreasing the model's likelihood to
33
+ * repeat the same line verbatim.
34
+ */
35
+ frequency_penalty?: number | null;
36
+ /**
37
+ * Whether to include reasoning in the response. This field is mutually exclusive
38
+ * with `reasoning_format`.
39
+ */
40
+ include_reasoning?: boolean | null;
41
+ /** Modify the likelihood of specified tokens appearing in the completion. */
42
+ logit_bias?: {
43
+ [key: string]: number;
44
+ } | null;
45
+ /**
46
+ * Whether to return log probabilities of the output tokens or not. If true,
47
+ * returns the log probabilities of each output token returned in the `content`
48
+ * of `message`.
49
+ */
50
+ logprobs?: boolean | null;
51
+ /**
52
+ * The maximum number of tokens that can be generated in the chat completion. The
53
+ * total length of input tokens and generated tokens is limited by the model's
54
+ * context length.
55
+ */
56
+ max_completion_tokens?: number | null;
57
+ /** Request metadata. */
58
+ metadata?: {
59
+ [key: string]: string;
60
+ } | null;
61
+ /**
62
+ * How many chat completion choices to generate for each input message.
63
+ * Currently only n=1 is supported.
64
+ */
65
+ n?: number | null;
66
+ /** Whether to enable parallel function calling during tool use. */
67
+ parallel_tool_calls?: boolean | null;
68
+ /**
69
+ * Number between -2.0 and 2.0. Positive values penalize new tokens based on
70
+ * whether they appear in the text so far, increasing the model's likelihood to
71
+ * talk about new topics.
72
+ */
73
+ presence_penalty?: number | null;
74
+ /**
75
+ * Controls reasoning effort for supported models.
76
+ *
77
+ * - qwen3 models: `'none'` to disable, `'default'` or null to enable
78
+ * - openai/gpt-oss models: `'low'`, `'medium'` (default), or `'high'`
79
+ */
80
+ reasoning_effort?: 'none' | 'default' | 'low' | 'medium' | 'high' | null;
81
+ /**
82
+ * Specifies how to output reasoning tokens.
83
+ * This field is mutually exclusive with `include_reasoning`.
84
+ */
85
+ reasoning_format?: 'hidden' | 'raw' | 'parsed' | null;
86
+ /**
87
+ * An object specifying the format that the model must output.
88
+ *
89
+ * - `json_schema` — enables Structured Outputs (preferred)
90
+ * - `json_object` — enables the older JSON mode
91
+ * - `text` — plain text output (default)
92
+ *
93
+ * @see https://console.groq.com/docs/structured-outputs
94
+ */
95
+ response_format?: ResponseFormatText | ResponseFormatJsonSchema | ResponseFormatJsonObject | null;
96
+ /** Settings for web search functionality when the model uses a web search tool. */
97
+ search_settings?: SearchSettings | null;
98
+ /**
99
+ * If specified, our system will make a best effort to sample deterministically,
100
+ * such that repeated requests with the same `seed` and parameters should return
101
+ * the same result.
102
+ */
103
+ seed?: number | null;
104
+ /**
105
+ * The service tier to use for the request.
106
+ *
107
+ * - `auto` — automatically select the highest tier available
108
+ * - `flex` — uses the flex tier, which will succeed or fail quickly
109
+ */
110
+ service_tier?: 'auto' | 'on_demand' | 'flex' | 'performance' | null;
111
+ /**
112
+ * Up to 4 sequences where the API will stop generating further tokens.
113
+ * The returned text will not contain the stop sequence.
114
+ */
115
+ stop?: string | null | Array<string>;
116
+ /** Whether to store the request for future use. */
117
+ store?: boolean | null;
118
+ /**
119
+ * Sampling temperature between 0 and 2. Higher values like 0.8 will make the
120
+ * output more random, while lower values like 0.2 will make it more focused
121
+ * and deterministic. We generally recommend altering this or top_p but not both.
122
+ */
123
+ temperature?: number | null;
124
+ /**
125
+ * Controls which (if any) tool is called by the model.
126
+ *
127
+ * - `none` — never call tools
128
+ * - `auto` — model decides (default when tools are present)
129
+ * - `required` — model must call tools
130
+ * - Named choice — forces a specific tool
131
+ */
132
+ tool_choice?: ChatCompletionToolChoiceOption | null;
133
+ /**
134
+ * An integer between 0 and 20 specifying the number of most likely tokens to
135
+ * return at each token position. `logprobs` must be set to `true` if this
136
+ * parameter is used.
137
+ */
138
+ top_logprobs?: number | null;
139
+ /**
140
+ * An alternative to sampling with temperature, called nucleus sampling, where the
141
+ * model considers the results of the tokens with top_p probability mass. So 0.1
142
+ * means only the tokens comprising the top 10% probability mass are considered.
143
+ */
144
+ top_p?: number | null;
145
+ /**
146
+ * A unique identifier representing your end-user, which can help monitor and
147
+ * detect abuse.
148
+ */
149
+ user?: string | null;
150
+ }
151
+ /**
152
+ * Internal options interface used for validation within the adapter.
153
+ * Extends provider options with required fields for API requests.
154
+ */
155
+ export interface InternalTextProviderOptions extends GroqTextProviderOptions {
156
+ /** An array of messages comprising the conversation. */
157
+ messages: Array<ChatCompletionMessageParam>;
158
+ /**
159
+ * The model name (e.g. "llama-3.3-70b-versatile", "openai/gpt-oss-120b").
160
+ * @see https://console.groq.com/docs/models
161
+ */
162
+ model: string;
163
+ /** Whether to stream partial message deltas as server-sent events. */
164
+ stream?: boolean | null;
165
+ /**
166
+ * Tools the model may call (functions, code_interpreter, etc).
167
+ * @see https://console.groq.com/docs/tool-use
168
+ */
169
+ tools?: Array<ChatCompletionTool>;
170
+ }
171
+ /**
172
+ * External provider options (what users pass in)
173
+ */
174
+ export type ExternalTextProviderOptions = GroqTextProviderOptions;
175
+ /**
176
+ * Validates text provider options.
177
+ * Basic validation stub — Groq API handles detailed validation.
178
+ */
179
+ export declare function validateTextProviderOptions(_options: InternalTextProviderOptions): void;
@@ -0,0 +1,6 @@
1
+ function validateTextProviderOptions(_options) {
2
+ }
3
+ export {
4
+ validateTextProviderOptions
5
+ };
6
+ //# sourceMappingURL=text-provider-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-provider-options.js","sources":["../../../src/text/text-provider-options.ts"],"sourcesContent":["import type {\n ChatCompletionMessageParam,\n ChatCompletionTool,\n ChatCompletionToolChoiceOption,\n CompoundCustom,\n Document,\n ResponseFormatJsonObject,\n ResponseFormatJsonSchema,\n ResponseFormatText,\n SearchSettings,\n} from '../message-types'\n\n/**\n * Groq-specific provider options for text/chat models.\n *\n * These options extend the standard Chat Completions API parameters\n * with Groq-specific features like compound models and search settings.\n *\n * @see https://console.groq.com/docs/api-reference#chat\n */\nexport interface GroqTextProviderOptions {\n /**\n * Whether to enable citations in the response. When enabled, the model will\n * include citations for information retrieved from provided documents or web\n * searches.\n */\n citation_options?: 'enabled' | 'disabled' | null\n\n /** Custom configuration of models and tools for Compound. */\n compound_custom?: CompoundCustom | null\n\n /**\n * If set to true, groq will return called tools without validating that the tool\n * is present in request.tools. tool_choice=required/none will still be enforced,\n * but the request cannot require a specific tool be used.\n */\n disable_tool_validation?: boolean\n\n /**\n * A list of documents to provide context for the conversation. Each document\n * contains text that can be referenced by the model.\n */\n documents?: Array<Document> | null\n\n /**\n * Number between -2.0 and 2.0. Positive values penalize new tokens based on their\n * existing frequency in the text so far, decreasing the model's likelihood to\n * repeat the same line verbatim.\n */\n frequency_penalty?: number | null\n\n /**\n * Whether to include reasoning in the response. This field is mutually exclusive\n * with `reasoning_format`.\n */\n include_reasoning?: boolean | null\n\n /** Modify the likelihood of specified tokens appearing in the completion. */\n logit_bias?: { [key: string]: number } | null\n\n /**\n * Whether to return log probabilities of the output tokens or not. If true,\n * returns the log probabilities of each output token returned in the `content`\n * of `message`.\n */\n logprobs?: boolean | null\n\n /**\n * The maximum number of tokens that can be generated in the chat completion. The\n * total length of input tokens and generated tokens is limited by the model's\n * context length.\n */\n max_completion_tokens?: number | null\n\n /** Request metadata. */\n metadata?: { [key: string]: string } | null\n\n /**\n * How many chat completion choices to generate for each input message.\n * Currently only n=1 is supported.\n */\n n?: number | null\n\n /** Whether to enable parallel function calling during tool use. */\n parallel_tool_calls?: boolean | null\n\n /**\n * Number between -2.0 and 2.0. Positive values penalize new tokens based on\n * whether they appear in the text so far, increasing the model's likelihood to\n * talk about new topics.\n */\n presence_penalty?: number | null\n\n /**\n * Controls reasoning effort for supported models.\n *\n * - qwen3 models: `'none'` to disable, `'default'` or null to enable\n * - openai/gpt-oss models: `'low'`, `'medium'` (default), or `'high'`\n */\n reasoning_effort?: 'none' | 'default' | 'low' | 'medium' | 'high' | null\n\n /**\n * Specifies how to output reasoning tokens.\n * This field is mutually exclusive with `include_reasoning`.\n */\n reasoning_format?: 'hidden' | 'raw' | 'parsed' | null\n\n /**\n * An object specifying the format that the model must output.\n *\n * - `json_schema` — enables Structured Outputs (preferred)\n * - `json_object` — enables the older JSON mode\n * - `text` — plain text output (default)\n *\n * @see https://console.groq.com/docs/structured-outputs\n */\n response_format?:\n | ResponseFormatText\n | ResponseFormatJsonSchema\n | ResponseFormatJsonObject\n | null\n\n /** Settings for web search functionality when the model uses a web search tool. */\n search_settings?: SearchSettings | null\n\n /**\n * If specified, our system will make a best effort to sample deterministically,\n * such that repeated requests with the same `seed` and parameters should return\n * the same result.\n */\n seed?: number | null\n\n /**\n * The service tier to use for the request.\n *\n * - `auto` — automatically select the highest tier available\n * - `flex` — uses the flex tier, which will succeed or fail quickly\n */\n service_tier?: 'auto' | 'on_demand' | 'flex' | 'performance' | null\n\n /**\n * Up to 4 sequences where the API will stop generating further tokens.\n * The returned text will not contain the stop sequence.\n */\n stop?: string | null | Array<string>\n\n /** Whether to store the request for future use. */\n store?: boolean | null\n\n /**\n * Sampling temperature between 0 and 2. Higher values like 0.8 will make the\n * output more random, while lower values like 0.2 will make it more focused\n * and deterministic. We generally recommend altering this or top_p but not both.\n */\n temperature?: number | null\n\n /**\n * Controls which (if any) tool is called by the model.\n *\n * - `none` — never call tools\n * - `auto` — model decides (default when tools are present)\n * - `required` — model must call tools\n * - Named choice — forces a specific tool\n */\n tool_choice?: ChatCompletionToolChoiceOption | null\n\n /**\n * An integer between 0 and 20 specifying the number of most likely tokens to\n * return at each token position. `logprobs` must be set to `true` if this\n * parameter is used.\n */\n top_logprobs?: number | null\n\n /**\n * An alternative to sampling with temperature, called nucleus sampling, where the\n * model considers the results of the tokens with top_p probability mass. So 0.1\n * means only the tokens comprising the top 10% probability mass are considered.\n */\n top_p?: number | null\n\n /**\n * A unique identifier representing your end-user, which can help monitor and\n * detect abuse.\n */\n user?: string | null\n}\n\n/**\n * Internal options interface used for validation within the adapter.\n * Extends provider options with required fields for API requests.\n */\nexport interface InternalTextProviderOptions extends GroqTextProviderOptions {\n /** An array of messages comprising the conversation. */\n messages: Array<ChatCompletionMessageParam>\n\n /**\n * The model name (e.g. \"llama-3.3-70b-versatile\", \"openai/gpt-oss-120b\").\n * @see https://console.groq.com/docs/models\n */\n model: string\n\n /** Whether to stream partial message deltas as server-sent events. */\n stream?: boolean | null\n\n /**\n * Tools the model may call (functions, code_interpreter, etc).\n * @see https://console.groq.com/docs/tool-use\n */\n tools?: Array<ChatCompletionTool>\n}\n\n/**\n * External provider options (what users pass in)\n */\nexport type ExternalTextProviderOptions = GroqTextProviderOptions\n\n/**\n * Validates text provider options.\n * Basic validation stub — Groq API handles detailed validation.\n */\nexport function validateTextProviderOptions(\n _options: InternalTextProviderOptions,\n): void {\n // Groq API handles detailed validation\n}\n"],"names":[],"mappings":"AA4NO,SAAS,4BACd,UACM;AAER;"}
@@ -0,0 +1,13 @@
1
+ import { Tool } from '@tanstack/ai';
2
+ import { ChatCompletionTool } from '../message-types.js';
3
+ export type FunctionTool = ChatCompletionTool;
4
+ /**
5
+ * Converts a standard Tool to Groq ChatCompletionTool format.
6
+ *
7
+ * Tool schemas are already converted to JSON Schema in the ai layer.
8
+ * We apply Groq-specific transformations for strict mode:
9
+ * - All properties in required array
10
+ * - Optional fields made nullable
11
+ * - additionalProperties: false
12
+ */
13
+ export declare function convertFunctionToolToAdapterFormat(tool: Tool): FunctionTool;
@@ -0,0 +1,29 @@
1
+ import { makeGroqStructuredOutputCompatible } from "../utils/schema-converter.js";
2
+ function convertFunctionToolToAdapterFormat(tool) {
3
+ const inputSchema = tool.inputSchema ?? {
4
+ type: "object",
5
+ properties: {},
6
+ required: []
7
+ };
8
+ if (inputSchema.type === "object" && !inputSchema.properties) {
9
+ inputSchema.properties = {};
10
+ }
11
+ const jsonSchema = makeGroqStructuredOutputCompatible(
12
+ inputSchema,
13
+ inputSchema.required || []
14
+ );
15
+ jsonSchema.additionalProperties = false;
16
+ return {
17
+ type: "function",
18
+ function: {
19
+ name: tool.name,
20
+ description: tool.description,
21
+ parameters: jsonSchema,
22
+ strict: true
23
+ }
24
+ };
25
+ }
26
+ export {
27
+ convertFunctionToolToAdapterFormat
28
+ };
29
+ //# sourceMappingURL=function-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"function-tool.js","sources":["../../../src/tools/function-tool.ts"],"sourcesContent":["import { makeGroqStructuredOutputCompatible } from '../utils/schema-converter'\nimport type { JSONSchema, Tool } from '@tanstack/ai'\nimport type { ChatCompletionTool } from '../message-types'\n\nexport type FunctionTool = ChatCompletionTool\n\n/**\n * Converts a standard Tool to Groq ChatCompletionTool format.\n *\n * Tool schemas are already converted to JSON Schema in the ai layer.\n * We apply Groq-specific transformations for strict mode:\n * - All properties in required array\n * - Optional fields made nullable\n * - additionalProperties: false\n */\nexport function convertFunctionToolToAdapterFormat(tool: Tool): FunctionTool {\n const inputSchema = (tool.inputSchema ?? {\n type: 'object',\n properties: {},\n required: [],\n }) as JSONSchema\n\n // Ensure object schemas always have properties (e.g. z.object({}) may produce { type: 'object' } without properties)\n if (inputSchema.type === 'object' && !inputSchema.properties) {\n inputSchema.properties = {}\n }\n\n const jsonSchema = makeGroqStructuredOutputCompatible(\n inputSchema,\n inputSchema.required || [],\n )\n\n jsonSchema.additionalProperties = false\n\n return {\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: jsonSchema,\n strict: true,\n },\n } satisfies FunctionTool\n}\n"],"names":[],"mappings":";AAeO,SAAS,mCAAmC,MAA0B;AAC3E,QAAM,cAAe,KAAK,eAAe;AAAA,IACvC,MAAM;AAAA,IACN,YAAY,CAAA;AAAA,IACZ,UAAU,CAAA;AAAA,EAAC;AAIb,MAAI,YAAY,SAAS,YAAY,CAAC,YAAY,YAAY;AAC5D,gBAAY,aAAa,CAAA;AAAA,EAC3B;AAEA,QAAM,aAAa;AAAA,IACjB;AAAA,IACA,YAAY,YAAY,CAAA;AAAA,EAAC;AAG3B,aAAW,uBAAuB;AAElC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,MACR,MAAM,KAAK;AAAA,MACX,aAAa,KAAK;AAAA,MAClB,YAAY;AAAA,MACZ,QAAQ;AAAA,IAAA;AAAA,EACV;AAEJ;"}
@@ -0,0 +1,2 @@
1
+ export { convertFunctionToolToAdapterFormat, type FunctionTool, } from './function-tool.js';
2
+ export { convertToolsToProviderFormat } from './tool-converter.js';
@@ -0,0 +1,7 @@
1
+ import { FunctionTool } from './function-tool.js';
2
+ import { Tool } from '@tanstack/ai';
3
+ /**
4
+ * Converts an array of standard Tools to Groq-specific format.
5
+ * Groq uses an OpenAI-compatible API, so we primarily support function tools.
6
+ */
7
+ export declare function convertToolsToProviderFormat(tools: Array<Tool>): Array<FunctionTool>;
@@ -0,0 +1,10 @@
1
+ import { convertFunctionToolToAdapterFormat } from "./function-tool.js";
2
+ function convertToolsToProviderFormat(tools) {
3
+ return tools.map((tool) => {
4
+ return convertFunctionToolToAdapterFormat(tool);
5
+ });
6
+ }
7
+ export {
8
+ convertToolsToProviderFormat
9
+ };
10
+ //# sourceMappingURL=tool-converter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-converter.js","sources":["../../../src/tools/tool-converter.ts"],"sourcesContent":["import { convertFunctionToolToAdapterFormat } from './function-tool'\nimport type { FunctionTool } from './function-tool'\nimport type { Tool } from '@tanstack/ai'\n\n/**\n * Converts an array of standard Tools to Groq-specific format.\n * Groq uses an OpenAI-compatible API, so we primarily support function tools.\n */\nexport function convertToolsToProviderFormat(\n tools: Array<Tool>,\n): Array<FunctionTool> {\n return tools.map((tool) => {\n return convertFunctionToolToAdapterFormat(tool)\n })\n}\n"],"names":[],"mappings":";AAQO,SAAS,6BACd,OACqB;AACrB,SAAO,MAAM,IAAI,CAAC,SAAS;AACzB,WAAO,mCAAmC,IAAI;AAAA,EAChD,CAAC;AACH;"}
@@ -0,0 +1,17 @@
1
+ import { default as Groq_SDK, ClientOptions } from 'groq-sdk';
2
+ export interface GroqClientConfig extends ClientOptions {
3
+ apiKey: string;
4
+ }
5
+ /**
6
+ * Creates a Groq SDK client instance
7
+ */
8
+ export declare function createGroqClient(config: GroqClientConfig): Groq_SDK;
9
+ /**
10
+ * Gets Groq API key from environment variables
11
+ * @throws Error if GROQ_API_KEY is not found
12
+ */
13
+ export declare function getGroqApiKeyFromEnv(): string;
14
+ /**
15
+ * Generates a unique ID with a prefix
16
+ */
17
+ export declare function generateId(prefix: string): string;
@@ -0,0 +1,23 @@
1
+ import Groq_SDK from "groq-sdk";
2
+ function createGroqClient(config) {
3
+ return new Groq_SDK(config);
4
+ }
5
+ function getGroqApiKeyFromEnv() {
6
+ const env = typeof globalThis !== "undefined" && globalThis.window?.env ? globalThis.window.env : typeof process !== "undefined" ? process.env : void 0;
7
+ const key = env?.GROQ_API_KEY;
8
+ if (!key) {
9
+ throw new Error(
10
+ "GROQ_API_KEY is required. Please set it in your environment variables or use the factory function with an explicit API key."
11
+ );
12
+ }
13
+ return key;
14
+ }
15
+ function generateId(prefix) {
16
+ return `${prefix}-${Date.now()}-${Math.random().toString(36).substring(7)}`;
17
+ }
18
+ export {
19
+ createGroqClient,
20
+ generateId,
21
+ getGroqApiKeyFromEnv
22
+ };
23
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sources":["../../../src/utils/client.ts"],"sourcesContent":["import Groq_SDK from 'groq-sdk'\nimport type { ClientOptions } from 'groq-sdk'\n\nexport interface GroqClientConfig extends ClientOptions {\n apiKey: string\n}\n\n/**\n * Creates a Groq SDK client instance\n */\nexport function createGroqClient(config: GroqClientConfig): Groq_SDK {\n return new Groq_SDK(config)\n}\n\n/**\n * Gets Groq API key from environment variables\n * @throws Error if GROQ_API_KEY is not found\n */\nexport function getGroqApiKeyFromEnv(): string {\n const env =\n typeof globalThis !== 'undefined' && (globalThis as any).window?.env\n ? (globalThis as any).window.env\n : typeof process !== 'undefined'\n ? process.env\n : undefined\n const key = env?.GROQ_API_KEY\n\n if (!key) {\n throw new Error(\n 'GROQ_API_KEY is required. Please set it in your environment variables or use the factory function with an explicit API key.',\n )\n }\n\n return key\n}\n\n/**\n * Generates a unique ID with a prefix\n */\nexport function generateId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).substring(7)}`\n}\n"],"names":[],"mappings":";AAUO,SAAS,iBAAiB,QAAoC;AACnE,SAAO,IAAI,SAAS,MAAM;AAC5B;AAMO,SAAS,uBAA+B;AAC7C,QAAM,MACJ,OAAO,eAAe,eAAgB,WAAmB,QAAQ,MAC5D,WAAmB,OAAO,MAC3B,OAAO,YAAY,cACjB,QAAQ,MACR;AACR,QAAM,MAAM,KAAK;AAEjB,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAEJ;AAEA,SAAO;AACT;AAKO,SAAS,WAAW,QAAwB;AACjD,SAAO,GAAG,MAAM,IAAI,KAAK,KAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,UAAU,CAAC,CAAC;AAC3E;"}
@@ -0,0 +1,2 @@
1
+ export { createGroqClient, getGroqApiKeyFromEnv, generateId, type GroqClientConfig, } from './client.js';
2
+ export { makeGroqStructuredOutputCompatible, transformNullsToUndefined, } from './schema-converter.js';
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Recursively transform null values to undefined in an object.
3
+ *
4
+ * This is needed because Groq's structured output requires all fields to be
5
+ * in the `required` array, with optional fields made nullable (type: ["string", "null"]).
6
+ * When Groq returns null for optional fields, we need to convert them back to
7
+ * undefined to match the original Zod schema expectations.
8
+ *
9
+ * @param obj - Object to transform
10
+ * @returns Object with nulls converted to undefined
11
+ */
12
+ export declare function transformNullsToUndefined<T>(obj: T): T;
13
+ /**
14
+ * Transform a JSON schema to be compatible with Groq's structured output requirements.
15
+ *
16
+ * Groq requires:
17
+ * - All properties must be in the `required` array
18
+ * - Optional fields should have null added to their type union
19
+ * - additionalProperties must be false for objects
20
+ *
21
+ * @param schema - JSON schema to transform
22
+ * @param originalRequired - Original required array (to know which fields were optional)
23
+ * @returns Transformed schema compatible with Groq structured output
24
+ */
25
+ export declare function makeGroqStructuredOutputCompatible(schema: Record<string, any>, originalRequired?: Array<string>): Record<string, any>;
@@ -0,0 +1,78 @@
1
+ function transformNullsToUndefined(obj) {
2
+ if (obj === null) {
3
+ return void 0;
4
+ }
5
+ if (Array.isArray(obj)) {
6
+ return obj.map((item) => transformNullsToUndefined(item));
7
+ }
8
+ if (typeof obj === "object") {
9
+ const result = {};
10
+ for (const [key, value] of Object.entries(obj)) {
11
+ const transformed = transformNullsToUndefined(value);
12
+ if (transformed !== void 0) {
13
+ result[key] = transformed;
14
+ }
15
+ }
16
+ return result;
17
+ }
18
+ return obj;
19
+ }
20
+ function makeGroqStructuredOutputCompatible(schema, originalRequired = []) {
21
+ const result = { ...schema };
22
+ if (result.type === "object") {
23
+ if (!result.properties) {
24
+ result.properties = {};
25
+ }
26
+ const properties = { ...result.properties };
27
+ const allPropertyNames = Object.keys(properties);
28
+ for (const propName of allPropertyNames) {
29
+ const prop = properties[propName];
30
+ const wasOptional = !originalRequired.includes(propName);
31
+ if (prop.type === "object" && prop.properties) {
32
+ properties[propName] = makeGroqStructuredOutputCompatible(
33
+ prop,
34
+ prop.required || []
35
+ );
36
+ } else if (prop.type === "array" && prop.items) {
37
+ properties[propName] = {
38
+ ...prop,
39
+ items: makeGroqStructuredOutputCompatible(
40
+ prop.items,
41
+ prop.items.required || []
42
+ )
43
+ };
44
+ } else if (wasOptional) {
45
+ if (prop.type && !Array.isArray(prop.type)) {
46
+ properties[propName] = {
47
+ ...prop,
48
+ type: [prop.type, "null"]
49
+ };
50
+ } else if (Array.isArray(prop.type) && !prop.type.includes("null")) {
51
+ properties[propName] = {
52
+ ...prop,
53
+ type: [...prop.type, "null"]
54
+ };
55
+ }
56
+ }
57
+ }
58
+ result.properties = properties;
59
+ if (allPropertyNames.length > 0) {
60
+ result.required = allPropertyNames;
61
+ } else {
62
+ delete result.required;
63
+ }
64
+ result.additionalProperties = false;
65
+ }
66
+ if (result.type === "array" && result.items) {
67
+ result.items = makeGroqStructuredOutputCompatible(
68
+ result.items,
69
+ result.items.required || []
70
+ );
71
+ }
72
+ return result;
73
+ }
74
+ export {
75
+ makeGroqStructuredOutputCompatible,
76
+ transformNullsToUndefined
77
+ };
78
+ //# sourceMappingURL=schema-converter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-converter.js","sources":["../../../src/utils/schema-converter.ts"],"sourcesContent":["/**\n * Recursively transform null values to undefined in an object.\n *\n * This is needed because Groq's structured output requires all fields to be\n * in the `required` array, with optional fields made nullable (type: [\"string\", \"null\"]).\n * When Groq returns null for optional fields, we need to convert them back to\n * undefined to match the original Zod schema expectations.\n *\n * @param obj - Object to transform\n * @returns Object with nulls converted to undefined\n */\nexport function transformNullsToUndefined<T>(obj: T): T {\n if (obj === null) {\n return undefined as unknown as T\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => transformNullsToUndefined(item)) as unknown as T\n }\n\n if (typeof obj === 'object') {\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n const transformed = transformNullsToUndefined(value)\n if (transformed !== undefined) {\n result[key] = transformed\n }\n }\n return result as T\n }\n\n return obj\n}\n\n/**\n * Transform a JSON schema to be compatible with Groq's structured output requirements.\n *\n * Groq requires:\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 objects\n *\n * @param schema - JSON schema to transform\n * @param originalRequired - Original required array (to know which fields were optional)\n * @returns Transformed schema compatible with Groq structured output\n */\nexport function makeGroqStructuredOutputCompatible(\n schema: Record<string, any>,\n originalRequired: Array<string> = [],\n): Record<string, any> {\n const result = { ...schema }\n\n if (result.type === 'object') {\n if (!result.properties) {\n result.properties = {}\n }\n const properties = { ...result.properties }\n const allPropertyNames = Object.keys(properties)\n\n for (const propName of allPropertyNames) {\n const prop = properties[propName]\n const wasOptional = !originalRequired.includes(propName)\n\n if (prop.type === 'object' && prop.properties) {\n properties[propName] = makeGroqStructuredOutputCompatible(\n prop,\n prop.required || [],\n )\n } else if (prop.type === 'array' && prop.items) {\n properties[propName] = {\n ...prop,\n items: makeGroqStructuredOutputCompatible(\n prop.items,\n prop.items.required || [],\n ),\n }\n } else if (wasOptional) {\n if (prop.type && !Array.isArray(prop.type)) {\n properties[propName] = {\n ...prop,\n type: [prop.type, 'null'],\n }\n } else if (Array.isArray(prop.type) && !prop.type.includes('null')) {\n properties[propName] = {\n ...prop,\n type: [...prop.type, 'null'],\n }\n }\n }\n }\n\n result.properties = properties\n // Groq rejects `required` when there are no properties, even if it's an empty array\n if (allPropertyNames.length > 0) {\n result.required = allPropertyNames\n } else {\n delete result.required\n }\n result.additionalProperties = false\n }\n\n if (result.type === 'array' && result.items) {\n result.items = makeGroqStructuredOutputCompatible(\n result.items,\n result.items.required || [],\n )\n }\n\n return result\n}\n"],"names":[],"mappings":"AAWO,SAAS,0BAA6B,KAAW;AACtD,MAAI,QAAQ,MAAM;AAChB,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO,IAAI,IAAI,CAAC,SAAS,0BAA0B,IAAI,CAAC;AAAA,EAC1D;AAEA,MAAI,OAAO,QAAQ,UAAU;AAC3B,UAAM,SAAkC,CAAA;AACxC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAA8B,GAAG;AACzE,YAAM,cAAc,0BAA0B,KAAK;AACnD,UAAI,gBAAgB,QAAW;AAC7B,eAAO,GAAG,IAAI;AAAA,MAChB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAcO,SAAS,mCACd,QACA,mBAAkC,IACb;AACrB,QAAM,SAAS,EAAE,GAAG,OAAA;AAEpB,MAAI,OAAO,SAAS,UAAU;AAC5B,QAAI,CAAC,OAAO,YAAY;AACtB,aAAO,aAAa,CAAA;AAAA,IACtB;AACA,UAAM,aAAa,EAAE,GAAG,OAAO,WAAA;AAC/B,UAAM,mBAAmB,OAAO,KAAK,UAAU;AAE/C,eAAW,YAAY,kBAAkB;AACvC,YAAM,OAAO,WAAW,QAAQ;AAChC,YAAM,cAAc,CAAC,iBAAiB,SAAS,QAAQ;AAEvD,UAAI,KAAK,SAAS,YAAY,KAAK,YAAY;AAC7C,mBAAW,QAAQ,IAAI;AAAA,UACrB;AAAA,UACA,KAAK,YAAY,CAAA;AAAA,QAAC;AAAA,MAEtB,WAAW,KAAK,SAAS,WAAW,KAAK,OAAO;AAC9C,mBAAW,QAAQ,IAAI;AAAA,UACrB,GAAG;AAAA,UACH,OAAO;AAAA,YACL,KAAK;AAAA,YACL,KAAK,MAAM,YAAY,CAAA;AAAA,UAAC;AAAA,QAC1B;AAAA,MAEJ,WAAW,aAAa;AACtB,YAAI,KAAK,QAAQ,CAAC,MAAM,QAAQ,KAAK,IAAI,GAAG;AAC1C,qBAAW,QAAQ,IAAI;AAAA,YACrB,GAAG;AAAA,YACH,MAAM,CAAC,KAAK,MAAM,MAAM;AAAA,UAAA;AAAA,QAE5B,WAAW,MAAM,QAAQ,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,MAAM,GAAG;AAClE,qBAAW,QAAQ,IAAI;AAAA,YACrB,GAAG;AAAA,YACH,MAAM,CAAC,GAAG,KAAK,MAAM,MAAM;AAAA,UAAA;AAAA,QAE/B;AAAA,MACF;AAAA,IACF;AAEA,WAAO,aAAa;AAEpB,QAAI,iBAAiB,SAAS,GAAG;AAC/B,aAAO,WAAW;AAAA,IACpB,OAAO;AACL,aAAO,OAAO;AAAA,IAChB;AACA,WAAO,uBAAuB;AAAA,EAChC;AAEA,MAAI,OAAO,SAAS,WAAW,OAAO,OAAO;AAC3C,WAAO,QAAQ;AAAA,MACb,OAAO;AAAA,MACP,OAAO,MAAM,YAAY,CAAA;AAAA,IAAC;AAAA,EAE9B;AAEA,SAAO;AACT;"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@tanstack/ai-groq",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Groq adapter for TanStack AI",
6
+ "author": "",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/TanStack/ai.git",
11
+ "directory": "packages/typescript/ai-groq"
12
+ },
13
+ "module": "./dist/esm/index.js",
14
+ "types": "./dist/esm/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/esm/index.d.ts",
18
+ "import": "./dist/esm/index.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "src"
24
+ ],
25
+ "scripts": {
26
+ "build": "vite build",
27
+ "clean": "premove ./build ./dist",
28
+ "lint:fix": "eslint ./src --fix",
29
+ "test:build": "publint --strict",
30
+ "test:eslint": "eslint ./src",
31
+ "test:lib": "vitest run",
32
+ "test:lib:dev": "pnpm test:lib --watch",
33
+ "test:types": "tsc"
34
+ },
35
+ "keywords": [
36
+ "ai",
37
+ "groq",
38
+ "tanstack",
39
+ "adapter"
40
+ ],
41
+ "devDependencies": {
42
+ "@vitest/coverage-v8": "4.0.14",
43
+ "vite": "^7.2.7"
44
+ },
45
+ "peerDependencies": {
46
+ "@tanstack/ai": "^0.6.3",
47
+ "zod": "^4.0.0"
48
+ },
49
+ "dependencies": {
50
+ "groq-sdk": "^0.37.0"
51
+ }
52
+ }