@tanstack/ai-groq 0.1.11 → 0.2.1
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.
- package/dist/esm/adapters/text.d.ts +30 -68
- package/dist/esm/adapters/text.js +31 -383
- package/dist/esm/adapters/text.js.map +1 -1
- package/dist/esm/message-types.d.ts +9 -96
- package/dist/esm/text/text-provider-options.d.ts +1 -26
- package/dist/esm/utils/client.d.ts +6 -8
- package/dist/esm/utils/client.js +15 -11
- package/dist/esm/utils/client.js.map +1 -1
- package/dist/esm/utils/index.d.ts +2 -1
- package/dist/esm/utils/schema-converter.js.map +1 -1
- package/package.json +4 -4
- package/src/adapters/text.ts +63 -552
- package/src/message-types.ts +9 -129
- package/src/text/text-provider-options.ts +0 -36
- package/src/utils/client.ts +18 -15
- package/src/utils/index.ts +2 -2
- package/src/utils/schema-converter.ts +2 -2
- package/dist/esm/text/text-provider-options.js +0 -6
- package/dist/esm/text/text-provider-options.js.map +0 -1
|
@@ -1,62 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Groq-specific message types for the Chat Completions API.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Groq's wire format is OpenAI Chat Completions plus a few Groq-specific
|
|
5
|
+
* extensions (compound tools, citation/service-tier provider options,
|
|
6
|
+
* etc.). These type definitions describe that wire shape directly — the
|
|
7
|
+
* Groq SDK was dropped in favour of pointing the OpenAI SDK at Groq's
|
|
8
|
+
* `/openai/v1` base URL, so this file is the source of truth for
|
|
9
|
+
* Groq-only fields rather than a mirror of an external SDK's types.
|
|
6
10
|
*
|
|
7
11
|
* @see https://console.groq.com/docs/api-reference#chat
|
|
8
12
|
*/
|
|
9
|
-
export interface ChatCompletionContentPartText {
|
|
10
|
-
/** The text content. */
|
|
11
|
-
text: string;
|
|
12
|
-
/** The type of the content part. */
|
|
13
|
-
type: 'text';
|
|
14
|
-
}
|
|
15
|
-
export interface ChatCompletionContentPartImage {
|
|
16
|
-
image_url: {
|
|
17
|
-
/** Either a URL of the image or the base64 encoded image data. */
|
|
18
|
-
url: string;
|
|
19
|
-
/** Specifies the detail level of the image. */
|
|
20
|
-
detail?: 'auto' | 'low' | 'high';
|
|
21
|
-
};
|
|
22
|
-
/** The type of the content part. */
|
|
23
|
-
type: 'image_url';
|
|
24
|
-
}
|
|
25
|
-
export interface ChatCompletionMessageToolCall {
|
|
26
|
-
/** The ID of the tool call. */
|
|
27
|
-
id: string;
|
|
28
|
-
/** The function that the model called. */
|
|
29
|
-
function: {
|
|
30
|
-
/**
|
|
31
|
-
* The arguments to call the function with, as generated by the model in JSON
|
|
32
|
-
* format. Note that the model does not always generate valid JSON, and may
|
|
33
|
-
* hallucinate parameters not defined by your function schema. Validate the
|
|
34
|
-
* arguments in your code before calling your function.
|
|
35
|
-
*/
|
|
36
|
-
arguments: string;
|
|
37
|
-
/** The name of the function to call. */
|
|
38
|
-
name: string;
|
|
39
|
-
};
|
|
40
|
-
/** The type of the tool. Currently, only `function` is supported. */
|
|
41
|
-
type: 'function';
|
|
42
|
-
}
|
|
43
|
-
export interface ChatCompletionRequestMessageContentPartDocument {
|
|
44
|
-
document: {
|
|
45
|
-
/** The JSON document data. */
|
|
46
|
-
data: {
|
|
47
|
-
[key: string]: unknown;
|
|
48
|
-
};
|
|
49
|
-
/** Optional unique identifier for the document. */
|
|
50
|
-
id?: string | null;
|
|
51
|
-
};
|
|
52
|
-
/** The type of the content part. */
|
|
53
|
-
type: 'document';
|
|
54
|
-
}
|
|
55
13
|
export type FunctionParameters = {
|
|
56
14
|
[key: string]: unknown;
|
|
57
15
|
};
|
|
58
16
|
export interface ChatCompletionNamedToolChoice {
|
|
59
|
-
|
|
17
|
+
/** Always `function` for a named tool choice. */
|
|
18
|
+
type: 'function';
|
|
19
|
+
function: {
|
|
60
20
|
/** The name of the function to call. */
|
|
61
21
|
name: string;
|
|
62
22
|
};
|
|
@@ -93,25 +53,6 @@ export interface FunctionDefinition {
|
|
|
93
53
|
* - Named tool choice — forces the model to call a specific tool
|
|
94
54
|
*/
|
|
95
55
|
export type ChatCompletionToolChoiceOption = 'none' | 'auto' | 'required' | ChatCompletionNamedToolChoice;
|
|
96
|
-
export type ChatCompletionContentPart = ChatCompletionContentPartText | ChatCompletionContentPartImage | ChatCompletionRequestMessageContentPartDocument;
|
|
97
|
-
export interface ChatCompletionAssistantMessageParam {
|
|
98
|
-
/** The role of the messages author, in this case `assistant`. */
|
|
99
|
-
role: 'assistant';
|
|
100
|
-
/**
|
|
101
|
-
* The contents of the assistant message. Required unless `tool_calls` or
|
|
102
|
-
* `function_call` is specified.
|
|
103
|
-
*/
|
|
104
|
-
content?: string | Array<ChatCompletionContentPartText> | null;
|
|
105
|
-
/** An optional name for the participant. */
|
|
106
|
-
name?: string;
|
|
107
|
-
/**
|
|
108
|
-
* The reasoning output by the assistant if reasoning_format was set to 'parsed'.
|
|
109
|
-
* This field is only useable with qwen3 models.
|
|
110
|
-
*/
|
|
111
|
-
reasoning?: string | null;
|
|
112
|
-
/** The tool calls generated by the model, such as function calls. */
|
|
113
|
-
tool_calls?: Array<ChatCompletionMessageToolCall>;
|
|
114
|
-
}
|
|
115
56
|
export interface ChatCompletionTool {
|
|
116
57
|
/**
|
|
117
58
|
* The type of the tool. `function`, `browser_search`, and `code_interpreter` are
|
|
@@ -120,34 +61,6 @@ export interface ChatCompletionTool {
|
|
|
120
61
|
type: 'function' | 'browser_search' | 'code_interpreter' | (string & {});
|
|
121
62
|
function?: FunctionDefinition;
|
|
122
63
|
}
|
|
123
|
-
export interface ChatCompletionToolMessageParam {
|
|
124
|
-
/** The contents of the tool message. */
|
|
125
|
-
content: string | Array<ChatCompletionContentPart>;
|
|
126
|
-
/** The role of the messages author, in this case `tool`. */
|
|
127
|
-
role: 'tool';
|
|
128
|
-
/** Tool call that this message is responding to. */
|
|
129
|
-
tool_call_id: string;
|
|
130
|
-
}
|
|
131
|
-
export interface ChatCompletionSystemMessageParam {
|
|
132
|
-
/** The contents of the system message. */
|
|
133
|
-
content: string | Array<ChatCompletionContentPartText>;
|
|
134
|
-
/** The role of the messages author, in this case `system`. */
|
|
135
|
-
role: 'system' | 'developer';
|
|
136
|
-
/** An optional name for the participant. */
|
|
137
|
-
name?: string;
|
|
138
|
-
}
|
|
139
|
-
export interface ChatCompletionUserMessageParam {
|
|
140
|
-
/** The contents of the user message. */
|
|
141
|
-
content: string | Array<ChatCompletionContentPart>;
|
|
142
|
-
/** The role of the messages author, in this case `user`. */
|
|
143
|
-
role: 'user';
|
|
144
|
-
/** An optional name for the participant. */
|
|
145
|
-
name?: string;
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Union of all supported chat completion message params.
|
|
149
|
-
*/
|
|
150
|
-
export type ChatCompletionMessageParam = ChatCompletionSystemMessageParam | ChatCompletionUserMessageParam | ChatCompletionAssistantMessageParam | ChatCompletionToolMessageParam;
|
|
151
64
|
export interface CompoundCustomModels {
|
|
152
65
|
/** Custom model to use for answering. */
|
|
153
66
|
answering_model?: string | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChatCompletionToolChoiceOption, CompoundCustom, Document, ResponseFormatJsonObject, ResponseFormatJsonSchema, ResponseFormatText, SearchSettings } from '../message-types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Groq-specific provider options for text/chat models.
|
|
4
4
|
*
|
|
@@ -148,32 +148,7 @@ export interface GroqTextProviderOptions {
|
|
|
148
148
|
*/
|
|
149
149
|
user?: string | null;
|
|
150
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
151
|
/**
|
|
172
152
|
* External provider options (what users pass in)
|
|
173
153
|
*/
|
|
174
154
|
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;
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export interface GroqClientConfig extends ClientOptions {
|
|
1
|
+
import { ClientOptions } from 'openai';
|
|
2
|
+
export interface GroqClientConfig extends Omit<ClientOptions, 'apiKey'> {
|
|
3
3
|
apiKey: string;
|
|
4
4
|
}
|
|
5
|
-
/**
|
|
6
|
-
* Creates a Groq SDK client instance
|
|
7
|
-
*/
|
|
8
|
-
export declare function createGroqClient(config: GroqClientConfig): Groq_SDK;
|
|
9
5
|
/**
|
|
10
6
|
* Gets Groq API key from environment variables
|
|
11
7
|
* @throws Error if GROQ_API_KEY is not found
|
|
12
8
|
*/
|
|
13
9
|
export declare function getGroqApiKeyFromEnv(): string;
|
|
14
10
|
/**
|
|
15
|
-
*
|
|
11
|
+
* Returns a Groq client config with Groq's OpenAI-compatible base URL
|
|
12
|
+
* applied when not already set. The Groq endpoint accepts the OpenAI SDK
|
|
13
|
+
* verbatim, so the adapter drives it via the OpenAI SDK with this baseURL.
|
|
16
14
|
*/
|
|
17
|
-
export declare function
|
|
15
|
+
export declare function withGroqDefaults(config: GroqClientConfig): GroqClientConfig;
|
package/dist/esm/utils/client.js
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import Groq_SDK from "groq-sdk";
|
|
3
|
-
function createGroqClient(config) {
|
|
4
|
-
return new Groq_SDK(config);
|
|
5
|
-
}
|
|
1
|
+
import { getApiKeyFromEnv } from "@tanstack/ai-utils";
|
|
6
2
|
function getGroqApiKeyFromEnv() {
|
|
7
|
-
|
|
3
|
+
try {
|
|
4
|
+
return getApiKeyFromEnv("GROQ_API_KEY");
|
|
5
|
+
} catch {
|
|
6
|
+
throw new Error(
|
|
7
|
+
"GROQ_API_KEY is required. Please set it in your environment variables or use the factory function with an explicit API key."
|
|
8
|
+
);
|
|
9
|
+
}
|
|
8
10
|
}
|
|
9
|
-
function
|
|
10
|
-
return
|
|
11
|
+
function withGroqDefaults(config) {
|
|
12
|
+
return {
|
|
13
|
+
...config,
|
|
14
|
+
baseURL: config.baseURL || "https://api.groq.com/openai/v1"
|
|
15
|
+
};
|
|
11
16
|
}
|
|
12
17
|
export {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
getGroqApiKeyFromEnv
|
|
18
|
+
getGroqApiKeyFromEnv,
|
|
19
|
+
withGroqDefaults
|
|
16
20
|
};
|
|
17
21
|
//# sourceMappingURL=client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sources":["../../../src/utils/client.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"client.js","sources":["../../../src/utils/client.ts"],"sourcesContent":["import { getApiKeyFromEnv } from '@tanstack/ai-utils'\nimport type { ClientOptions } from 'openai'\n\nexport interface GroqClientConfig extends Omit<ClientOptions, 'apiKey'> {\n apiKey: string\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 try {\n return getApiKeyFromEnv('GROQ_API_KEY')\n } catch {\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\n/**\n * Returns a Groq client config with Groq's OpenAI-compatible base URL\n * applied when not already set. The Groq endpoint accepts the OpenAI SDK\n * verbatim, so the adapter drives it via the OpenAI SDK with this baseURL.\n */\nexport function withGroqDefaults(config: GroqClientConfig): GroqClientConfig {\n return {\n ...config,\n baseURL: config.baseURL || 'https://api.groq.com/openai/v1',\n }\n}\n"],"names":[],"mappings":";AAWO,SAAS,uBAA+B;AAC7C,MAAI;AACF,WAAO,iBAAiB,cAAc;AAAA,EACxC,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAEJ;AACF;AAOO,SAAS,iBAAiB,QAA4C;AAC3E,SAAO;AAAA,IACL,GAAG;AAAA,IACH,SAAS,OAAO,WAAW;AAAA,EAAA;AAE/B;"}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { getGroqApiKeyFromEnv, withGroqDefaults, type GroqClientConfig, } from './client.js';
|
|
2
|
+
export { generateId } from '@tanstack/ai-utils';
|
|
2
3
|
export { makeGroqStructuredOutputCompatible, transformNullsToUndefined, } from './schema-converter.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-converter.js","sources":["../../../src/utils/schema-converter.ts"],"sourcesContent":["import { makeStructuredOutputCompatible } from '@tanstack/openai-base'\nimport { transformNullsToUndefined } from '@tanstack/ai-utils'\n\nexport { transformNullsToUndefined }\n\n/**\n * Recursively removes `required: []` from a schema object.\n * Groq rejects `required` when it is an empty array, even though\n * OpenAI-compatible schemas allow it.\n */\nfunction removeEmptyRequired(schema: Record<string, any>): Record<string, any> {\n const result = { ...schema }\n\n if (Array.isArray(result.required) && result.required.length === 0) {\n delete result.required\n }\n\n if (result.properties && typeof result.properties === 'object') {\n const properties: Record<string, any> = {}\n for (const [key, value] of Object.entries(\n result.properties as Record<string, any>,\n )) {\n properties[key] =\n typeof value === 'object' && value !== null && !Array.isArray(value)\n ? removeEmptyRequired(value)\n : value\n }\n result.properties = properties\n }\n\n if (\n result.items &&\n typeof result.items === 'object' &&\n !Array.isArray(result.items)\n ) {\n result.items = removeEmptyRequired(result.items)\n }\n\n // Recurse into combinator arrays (anyOf, oneOf, allOf)\n for (const keyword of ['anyOf', 'oneOf', 'allOf'] as const) {\n if (Array.isArray(result[keyword])) {\n result[keyword] = result[keyword].map((entry: Record<string, any>) =>\n removeEmptyRequired(entry),\n )\n }\n }\n\n // Recurse into additionalProperties if it's a schema object\n if (\n result.additionalProperties &&\n typeof result.additionalProperties === 'object' &&\n !Array.isArray(result.additionalProperties)\n ) {\n result.additionalProperties = removeEmptyRequired(\n result.additionalProperties,\n )\n }\n\n return result\n}\n\n/**\n * Recursively normalise object schemas so any `{ type: 'object' }` node\n * without `properties` gets an empty `properties: {}` object. The\n * openai-base transformer only descends into objects that already have\n * `properties` set, so a Zod `z.object({})` nested inside `properties`,\n * `items`, `additionalProperties`, or a combinator branch would otherwise\n * skip the strict-mode rewrite and fail Groq validation.\n */\nfunction normalizeObjectSchemas(\n schema: Record<string, any>,\n): Record<string, any> {\n const result: Record<string, any> =\n schema.type === 'object' && !schema.properties\n ? { ...schema, properties: {} }\n : { ...schema }\n\n if (result.properties && typeof result.properties === 'object') {\n result.properties = Object.fromEntries(\n Object.entries(result.properties as Record<string, any>).map(\n ([key, value]) => [\n key,\n typeof value === 'object' && value !== null && !Array.isArray(value)\n ? normalizeObjectSchemas(value)\n : value,\n ],\n ),\n )\n }\n\n if (\n result.items &&\n typeof result.items === 'object' &&\n !Array.isArray(result.items)\n ) {\n result.items = normalizeObjectSchemas(result.items)\n }\n\n for (const keyword of ['anyOf', 'oneOf', 'allOf'] as const) {\n const branch = result[keyword]\n if (Array.isArray(branch)) {\n result[keyword] = branch.map((entry) =>\n typeof entry === 'object' && entry !== null\n ? normalizeObjectSchemas(entry as Record<string, any>)\n : entry,\n )\n }\n }\n\n if (\n result.additionalProperties &&\n typeof result.additionalProperties === 'object' &&\n !Array.isArray(result.additionalProperties)\n ) {\n result.additionalProperties = normalizeObjectSchemas(\n result.additionalProperties as Record<string, any>,\n )\n }\n\n return result\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 * - `required` must be omitted (not empty array) when there are no properties\n *\n * Delegates to the shared OpenAI-compatible transformer and applies the\n * Groq-specific quirk of removing empty `required` arrays.\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 // Recursively patch every `{ type: 'object' }` node so the openai-base\n // transformer descends into nested empty objects too.\n const normalised = normalizeObjectSchemas(schema)\n\n const result = makeStructuredOutputCompatible(normalised, originalRequired)\n\n // Groq rejects `required` when it is an empty array\n return removeEmptyRequired(result)\n}\n"],"names":[],"mappings":";;AAUA,SAAS,oBAAoB,QAAkD;AAC7E,QAAM,SAAS,EAAE,GAAG,OAAA;AAEpB,MAAI,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS,WAAW,GAAG;AAClE,WAAO,OAAO;AAAA,EAChB;AAEA,MAAI,OAAO,cAAc,OAAO,OAAO,eAAe,UAAU;AAC9D,UAAM,aAAkC,CAAA;AACxC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO;AAAA,MAChC,OAAO;AAAA,IAAA,GACN;AACD,iBAAW,GAAG,IACZ,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,IAC/D,oBAAoB,KAAK,IACzB;AAAA,IACR;AACA,WAAO,aAAa;AAAA,EACtB;AAEA,MACE,OAAO,SACP,OAAO,OAAO,UAAU,YACxB,CAAC,MAAM,QAAQ,OAAO,KAAK,GAC3B;AACA,WAAO,QAAQ,oBAAoB,OAAO,KAAK;AAAA,EACjD;AAGA,aAAW,WAAW,CAAC,SAAS,SAAS,OAAO,GAAY;AAC1D,QAAI,MAAM,QAAQ,OAAO,OAAO,CAAC,GAAG;AAClC,aAAO,OAAO,IAAI,OAAO,OAAO,EAAE;AAAA,QAAI,CAAC,UACrC,oBAAoB,KAAK;AAAA,MAAA;AAAA,IAE7B;AAAA,EACF;AAGA,MACE,OAAO,wBACP,OAAO,OAAO,yBAAyB,YACvC,CAAC,MAAM,QAAQ,OAAO,oBAAoB,GAC1C;AACA,WAAO,uBAAuB;AAAA,MAC5B,OAAO;AAAA,IAAA;AAAA,EAEX;AAEA,SAAO;AACT;AAUA,SAAS,uBACP,QACqB;AACrB,QAAM,SACJ,OAAO,SAAS,YAAY,CAAC,OAAO,aAChC,EAAE,GAAG,QAAQ,YAAY,CAAA,EAAC,IAC1B,EAAE,GAAG,OAAA;AAEX,MAAI,OAAO,cAAc,OAAO,OAAO,eAAe,UAAU;AAC9D,WAAO,aAAa,OAAO;AAAA,MACzB,OAAO,QAAQ,OAAO,UAAiC,EAAE;AAAA,QACvD,CAAC,CAAC,KAAK,KAAK,MAAM;AAAA,UAChB;AAAA,UACA,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,IAC/D,uBAAuB,KAAK,IAC5B;AAAA,QAAA;AAAA,MACN;AAAA,IACF;AAAA,EAEJ;AAEA,MACE,OAAO,SACP,OAAO,OAAO,UAAU,YACxB,CAAC,MAAM,QAAQ,OAAO,KAAK,GAC3B;AACA,WAAO,QAAQ,uBAAuB,OAAO,KAAK;AAAA,EACpD;AAEA,aAAW,WAAW,CAAC,SAAS,SAAS,OAAO,GAAY;AAC1D,UAAM,SAAS,OAAO,OAAO;AAC7B,QAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,aAAO,OAAO,IAAI,OAAO;AAAA,QAAI,CAAC,UAC5B,OAAO,UAAU,YAAY,UAAU,OACnC,uBAAuB,KAA4B,IACnD;AAAA,MAAA;AAAA,IAER;AAAA,EACF;AAEA,MACE,OAAO,wBACP,OAAO,OAAO,yBAAyB,YACvC,CAAC,MAAM,QAAQ,OAAO,oBAAoB,GAC1C;AACA,WAAO,uBAAuB;AAAA,MAC5B,OAAO;AAAA,IAAA;AAAA,EAEX;AAEA,SAAO;AACT;AAkBO,SAAS,mCACd,QACA,mBAAkC,IACb;AAGrB,QAAM,aAAa,uBAAuB,MAAM;AAEhD,QAAM,SAAS,+BAA+B,YAAY,gBAAgB;AAG1E,SAAO,oBAAoB,MAAM;AACnC;"}
|
|
1
|
+
{"version":3,"file":"schema-converter.js","sources":["../../../src/utils/schema-converter.ts"],"sourcesContent":["import { makeStructuredOutputCompatible } from '@tanstack/openai-base'\nimport { transformNullsToUndefined } from '@tanstack/ai-utils'\n\nexport { transformNullsToUndefined }\n\n/**\n * Recursively removes `required: []` from a schema object.\n * Groq rejects `required` when it is an empty array, even though\n * OpenAI-compatible schemas allow it.\n */\nfunction removeEmptyRequired(schema: Record<string, any>): Record<string, any> {\n const result = { ...schema }\n\n if (Array.isArray(result.required) && result.required.length === 0) {\n delete result.required\n }\n\n if (result.properties && typeof result.properties === 'object') {\n const properties: Record<string, any> = {}\n for (const [key, value] of Object.entries(\n result.properties as Record<string, any>,\n )) {\n properties[key] =\n typeof value === 'object' && value !== null && !Array.isArray(value)\n ? removeEmptyRequired(value)\n : value\n }\n result.properties = properties\n }\n\n if (\n result.items &&\n typeof result.items === 'object' &&\n !Array.isArray(result.items)\n ) {\n result.items = removeEmptyRequired(result.items)\n }\n\n // Recurse into combinator arrays (anyOf, oneOf, allOf)\n for (const keyword of ['anyOf', 'oneOf', 'allOf'] as const) {\n if (Array.isArray(result[keyword])) {\n result[keyword] = result[keyword].map((entry: Record<string, any>) =>\n removeEmptyRequired(entry),\n )\n }\n }\n\n // Recurse into additionalProperties if it's a schema object\n if (\n result.additionalProperties &&\n typeof result.additionalProperties === 'object' &&\n !Array.isArray(result.additionalProperties)\n ) {\n result.additionalProperties = removeEmptyRequired(\n result.additionalProperties,\n )\n }\n\n return result\n}\n\n/**\n * Recursively normalise object schemas so any `{ type: 'object' }` node\n * without `properties` gets an empty `properties: {}` object. The\n * ai-openai-base transformer only descends into objects that already have\n * `properties` set, so a Zod `z.object({})` nested inside `properties`,\n * `items`, `additionalProperties`, or a combinator branch would otherwise\n * skip the strict-mode rewrite and fail Groq validation.\n */\nfunction normalizeObjectSchemas(\n schema: Record<string, any>,\n): Record<string, any> {\n const result: Record<string, any> =\n schema.type === 'object' && !schema.properties\n ? { ...schema, properties: {} }\n : { ...schema }\n\n if (result.properties && typeof result.properties === 'object') {\n result.properties = Object.fromEntries(\n Object.entries(result.properties as Record<string, any>).map(\n ([key, value]) => [\n key,\n typeof value === 'object' && value !== null && !Array.isArray(value)\n ? normalizeObjectSchemas(value)\n : value,\n ],\n ),\n )\n }\n\n if (\n result.items &&\n typeof result.items === 'object' &&\n !Array.isArray(result.items)\n ) {\n result.items = normalizeObjectSchemas(result.items)\n }\n\n for (const keyword of ['anyOf', 'oneOf', 'allOf'] as const) {\n const branch = result[keyword]\n if (Array.isArray(branch)) {\n result[keyword] = branch.map((entry) =>\n typeof entry === 'object' && entry !== null\n ? normalizeObjectSchemas(entry as Record<string, any>)\n : entry,\n )\n }\n }\n\n if (\n result.additionalProperties &&\n typeof result.additionalProperties === 'object' &&\n !Array.isArray(result.additionalProperties)\n ) {\n result.additionalProperties = normalizeObjectSchemas(\n result.additionalProperties as Record<string, any>,\n )\n }\n\n return result\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 * - `required` must be omitted (not empty array) when there are no properties\n *\n * Delegates to the shared OpenAI-compatible transformer and applies the\n * Groq-specific quirk of removing empty `required` arrays.\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 // Recursively patch every `{ type: 'object' }` node so the ai-openai-base\n // transformer descends into nested empty objects too.\n const normalised = normalizeObjectSchemas(schema)\n\n const result = makeStructuredOutputCompatible(normalised, originalRequired)\n\n // Groq rejects `required` when it is an empty array\n return removeEmptyRequired(result)\n}\n"],"names":[],"mappings":";;AAUA,SAAS,oBAAoB,QAAkD;AAC7E,QAAM,SAAS,EAAE,GAAG,OAAA;AAEpB,MAAI,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS,WAAW,GAAG;AAClE,WAAO,OAAO;AAAA,EAChB;AAEA,MAAI,OAAO,cAAc,OAAO,OAAO,eAAe,UAAU;AAC9D,UAAM,aAAkC,CAAA;AACxC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO;AAAA,MAChC,OAAO;AAAA,IAAA,GACN;AACD,iBAAW,GAAG,IACZ,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,IAC/D,oBAAoB,KAAK,IACzB;AAAA,IACR;AACA,WAAO,aAAa;AAAA,EACtB;AAEA,MACE,OAAO,SACP,OAAO,OAAO,UAAU,YACxB,CAAC,MAAM,QAAQ,OAAO,KAAK,GAC3B;AACA,WAAO,QAAQ,oBAAoB,OAAO,KAAK;AAAA,EACjD;AAGA,aAAW,WAAW,CAAC,SAAS,SAAS,OAAO,GAAY;AAC1D,QAAI,MAAM,QAAQ,OAAO,OAAO,CAAC,GAAG;AAClC,aAAO,OAAO,IAAI,OAAO,OAAO,EAAE;AAAA,QAAI,CAAC,UACrC,oBAAoB,KAAK;AAAA,MAAA;AAAA,IAE7B;AAAA,EACF;AAGA,MACE,OAAO,wBACP,OAAO,OAAO,yBAAyB,YACvC,CAAC,MAAM,QAAQ,OAAO,oBAAoB,GAC1C;AACA,WAAO,uBAAuB;AAAA,MAC5B,OAAO;AAAA,IAAA;AAAA,EAEX;AAEA,SAAO;AACT;AAUA,SAAS,uBACP,QACqB;AACrB,QAAM,SACJ,OAAO,SAAS,YAAY,CAAC,OAAO,aAChC,EAAE,GAAG,QAAQ,YAAY,CAAA,EAAC,IAC1B,EAAE,GAAG,OAAA;AAEX,MAAI,OAAO,cAAc,OAAO,OAAO,eAAe,UAAU;AAC9D,WAAO,aAAa,OAAO;AAAA,MACzB,OAAO,QAAQ,OAAO,UAAiC,EAAE;AAAA,QACvD,CAAC,CAAC,KAAK,KAAK,MAAM;AAAA,UAChB;AAAA,UACA,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,IAC/D,uBAAuB,KAAK,IAC5B;AAAA,QAAA;AAAA,MACN;AAAA,IACF;AAAA,EAEJ;AAEA,MACE,OAAO,SACP,OAAO,OAAO,UAAU,YACxB,CAAC,MAAM,QAAQ,OAAO,KAAK,GAC3B;AACA,WAAO,QAAQ,uBAAuB,OAAO,KAAK;AAAA,EACpD;AAEA,aAAW,WAAW,CAAC,SAAS,SAAS,OAAO,GAAY;AAC1D,UAAM,SAAS,OAAO,OAAO;AAC7B,QAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,aAAO,OAAO,IAAI,OAAO;AAAA,QAAI,CAAC,UAC5B,OAAO,UAAU,YAAY,UAAU,OACnC,uBAAuB,KAA4B,IACnD;AAAA,MAAA;AAAA,IAER;AAAA,EACF;AAEA,MACE,OAAO,wBACP,OAAO,OAAO,yBAAyB,YACvC,CAAC,MAAM,QAAQ,OAAO,oBAAoB,GAC1C;AACA,WAAO,uBAAuB;AAAA,MAC5B,OAAO;AAAA,IAAA;AAAA,EAEX;AAEA,SAAO;AACT;AAkBO,SAAS,mCACd,QACA,mBAAkC,IACb;AAGrB,QAAM,aAAa,uBAAuB,MAAM;AAEhD,QAAM,SAAS,+BAA+B,YAAY,gBAAgB;AAG1E,SAAO,oBAAoB,MAAM;AACnC;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/ai-groq",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Groq adapter for TanStack AI",
|
|
6
6
|
"author": "",
|
|
@@ -38,12 +38,12 @@
|
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"zod": "^4.0.0",
|
|
41
|
-
"@tanstack/ai": "^0.
|
|
41
|
+
"@tanstack/ai": "^0.18.0"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"
|
|
44
|
+
"openai": "^6.9.1",
|
|
45
45
|
"@tanstack/ai-utils": "0.2.0",
|
|
46
|
-
"@tanstack/openai-base": "0.
|
|
46
|
+
"@tanstack/openai-base": "0.3.1"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"build": "vite build",
|