Skip to content

feat(ai-groq): Add Groq adapter package#332

Merged
AlemTuzlak merged 4 commits intoTanStack:mainfrom
dhamivibez:adapter/groq
Mar 6, 2026
Merged

feat(ai-groq): Add Groq adapter package#332
AlemTuzlak merged 4 commits intoTanStack:mainfrom
dhamivibez:adapter/groq

Conversation

@dhamivibez
Copy link
Contributor

@dhamivibez dhamivibez commented Mar 4, 2026

Adds a new @tanstack/ai-groq package for Groq AI model integration. This package provides a tree-shakeable text adapter, supporting streaming chat completions, structured output, and tool usage.

🎯 Changes

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm run test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • New Features
    • Added @tanstack/ai-groq adapter: streaming text/chat, structured JSON output, function/tool calling, and multimodal input; supports multiple Groq chat models with tree-shakeable exports.
  • Documentation
    • New README with installation, setup, usage examples, supported models, and features.
  • Examples
    • Example app updated to include Groq providers and UI error banner for adapter errors.
  • Tests
    • Comprehensive test suite for Groq adapter behavior.
  • Chores
    • Added changeset and package metadata for publishing.

Adds a new `@tanstack/ai-groq` package for Groq AI model integration.
This package provides a tree-shakeable text adapter, supporting
streaming chat completions, structured output, and tool usage.
@dhamivibez dhamivibez requested a review from a team March 4, 2026 22:44
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 4, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Adds a new TypeScript package @tanstack/ai-groq implementing a Groq text/chat adapter with streaming and structured-output support, comprehensive Groq-specific types and model metadata, tool conversion utilities, client/schema helpers, test coverage, and package/configuration files.

Changes

Cohort / File(s) Summary
Package Setup
\.changeset/free-impalas-doubt.md, packages/typescript/ai-groq/package.json, packages/typescript/ai-groq/tsconfig.json, packages/typescript/ai-groq/vite.config.ts, packages/typescript/ai-groq/vitest.config.ts, packages/typescript/ai-groq/README.md
New package metadata, build/test configuration, release changeset, and README for @tanstack/ai-groq.
Core Adapter Implementation
packages/typescript/ai-groq/src/adapters/text.ts, packages/typescript/ai-groq/src/index.ts
Adds GroqTextAdapter with streaming and structuredOutput APIs, option mapping, message conversion, factories (createGroqText, groqText), and re-exports public API surface.
Type Definitions & Model Metadata
packages/typescript/ai-groq/src/message-types.ts, packages/typescript/ai-groq/src/model-meta.ts, packages/typescript/ai-groq/src/text/text-provider-options.ts
Introduces extensive Groq-specific TypeScript types for messages, tools, response formats, provider options, and a large set of model metadata and model-specific type mappings.
Tools
packages/typescript/ai-groq/src/tools/function-tool.ts, packages/typescript/ai-groq/src/tools/tool-converter.ts, packages/typescript/ai-groq/src/tools/index.ts
Adds conversion utilities to map TanStack Tool definitions to Groq-compatible function tool formats and centralizes tool exports.
Utilities
packages/typescript/ai-groq/src/utils/client.ts, packages/typescript/ai-groq/src/utils/schema-converter.ts, packages/typescript/ai-groq/src/utils/index.ts
Adds Groq client creation, env API key resolution, ID generation, schema converter to make JSON schemas Groq-compatible, and null→undefined transformer; re-export barrel.
Tests
packages/typescript/ai-groq/tests/groq-adapter.test.ts
Comprehensive tests and mocks covering adapter creation, streaming events, tool calls, error handling, and AG-UI event sequencing.
Examples Integration
examples/ts-react-chat/package.json, examples/ts-react-chat/src/lib/model-selection.ts, examples/ts-react-chat/src/routes/api.tanchat.ts, examples/ts-react-chat/src/routes/index.tsx
Adds @tanstack/ai-groq as an example dependency, exposes new Groq models in UI, wires groqText provider branch, and surfaces error handling in the chat UI.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Adapter as Groq Text Adapter
    participant SDK as Groq SDK Client
    participant API as Groq API

    Client->>Adapter: chatStream(options)
    Adapter->>Adapter: mapTextOptionsToGroq(), convertMessageToGroq()
    Adapter->>SDK: chat.completions.create(request)
    SDK->>API: Stream Request

    loop stream chunks
        API-->>SDK: chunk (content / tool_call / finish)
        SDK-->>Adapter: chunk
        Adapter->>Adapter: processGroqStreamChunks()
        Adapter->>Client: emit StreamChunk (TEXT_MESSAGE_CONTENT / TOOL_* / etc.)
    end

    API-->>SDK: [DONE]
    SDK-->>Adapter: final response
    Adapter->>Client: emit RUN_FINISHED
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 A little adapter hops with glee,

Mapping messages to Groq for thee,
Streams that sparkle, schemas that bend,
Tools converted, tests to the end,
Hooray — our chat garden grows again!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding a new Groq adapter package for the TanStack AI framework.
Description check ✅ Passed The description follows the required template with all sections completed: changes explained, contributing guide checklist confirmed, and changeset generated for release impact.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (4)
packages/typescript/ai-groq/src/text/text-provider-options.ts (1)

221-225: validateTextProviderOptions is currently a no-op despite documented invariants.

Add minimal preflight checks for constraints already documented in this file (e.g., include_reasoning vs reasoning_format, top_logprobs requiring logprobs, and n === 1) so invalid configs fail fast.

💡 Suggested validation baseline
 export function validateTextProviderOptions(
-  _options: InternalTextProviderOptions,
+  options: InternalTextProviderOptions,
 ): void {
-  // Groq API handles detailed validation
+  if (
+    options.include_reasoning !== undefined &&
+    options.include_reasoning !== null &&
+    options.reasoning_format !== undefined &&
+    options.reasoning_format !== null
+  ) {
+    throw new Error(
+      "Cannot set both 'include_reasoning' and 'reasoning_format' in the same request.",
+    )
+  }
+
+  if (
+    options.top_logprobs !== undefined &&
+    options.top_logprobs !== null &&
+    options.logprobs !== true
+  ) {
+    throw new Error("'top_logprobs' requires 'logprobs: true'.")
+  }
+
+  if (options.n !== undefined && options.n !== null && options.n !== 1) {
+    throw new Error("Groq currently supports only 'n = 1'.")
+  }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/src/text/text-provider-options.ts` around lines
221 - 225, The validateTextProviderOptions function is currently a no-op;
implement fast-fail checks on InternalTextProviderOptions: ensure if
options.include_reasoning is true then options.reasoning_format is
set/non-empty; ensure if options.top_logprobs is provided (>0) then
options.logprobs is also provided/true; ensure options.n (if provided) equals 1
(reject values !== 1); throw a clear Error with descriptive message identifying
the offending field (use the function validateTextProviderOptions to locate the
change) so invalid configs fail fast.
packages/typescript/ai-groq/src/model-meta.ts (2)

37-305: Model constant identifiers don’t follow the repository camelCase naming rule.

Please rename these const variables to camelCase for consistency with the codebase convention.

As per coding guidelines "**/*.{ts,tsx,js,jsx}: Use camelCase for function and variable names throughout the codebase".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/src/model-meta.ts` around lines 37 - 305, The
model constant identifiers use SCREAMING_SNAKE_CASE but must follow the repo
camelCase convention; rename each constant (e.g., LLAMA_3_3_70B_VERSATILE →
llama3_3_70bVersatile, LLAMA_4_MAVERICK_17B_128E_INSTRUCT →
llama4Maverick17b128eInstruct, LLAMA_4_SCOUT_17B_16E_INSTRUCT →
llama4Scout17b16eInstruct, LLAMA_GUARD_4_12B → llamaGuard4_12b,
LLAMA_PROMPT_GUARD_2_86M → llamaPromptGuard2_86m, LLAMA_3_1_8B_INSTANT →
llama3_1_8bInstant, LLAMA_PROMPT_GUARD_2_22M → llamaPromptGuard2_22m,
GPT_OSS_120B → gptOss120b, GPT_OSS_SAFEGUARD_20B → gptOssSafeguard20b,
GPT_OSS_20B → gptOss20b, KIMI_K2_INSTRUCT_0905 → kimiK2Instruct0905, QWEN3_32B →
qwen3_32b) keeping the object contents and "as const satisfies
ModelMeta<GroqTextProviderOptions>" intact; then update all
references/imports/usages across the codebase to the new camelCase names
(including any exports or registration maps) to avoid breaking references and
run typechecks to ensure no missed usages.

350-362: ResolveProviderOptions currently doesn’t provide real per-model option narrowing.

Since every key maps to GroqTextProviderOptions, model selection does not change allowed option types at compile time. Consider mapping known models to model-specific option subsets and keeping a generic fallback for unknown models.

Based on learnings: "use mapped types over the known ... keys with a Record fallback ... to preserve per-model type safety."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/src/model-meta.ts` around lines 350 - 362, Change
the provider-options mapping to preserve per-model narrowing by creating a
merged options map (e.g. name it ProviderOptionsMap) that is a Record<string,
GroqTextProviderOptions> fallback intersected with a mapped type over (typeof
GROQ_CHAT_MODELS)[number] that assigns model-specific option types for known
models; update GroqChatModelProviderOptionsByName (or replace it) with that
ProviderOptionsMap and change ResolveProviderOptions<TModel extends string> to
use ProviderOptionsMap (TModel extends keyof ProviderOptionsMap ?
ProviderOptionsMap[TModel] : GroqTextProviderOptions). Edit the types referenced
(ResolveProviderOptions, GroqChatModelProviderOptionsByName, GROQ_CHAT_MODELS,
GroqTextProviderOptions) so known models get specific option subsets while
unknown models fall back to the generic GroqTextProviderOptions.
packages/typescript/ai-groq/src/adapters/text.ts (1)

119-123: Avoid raw console error dumps from shared adapter runtime.

Logging full error objects/stacks here can leak provider metadata and pollute consumer logs; prefer sanitized structured errors (or debug-gated logging only).

Also applies to: 182-183, 376-377

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/src/adapters/text.ts` around lines 119 - 123,
Replace raw console.error dumps in the chatStream error handling with sanitized,
structured logging: in the block that prints ">>> chatStream: Fatal error during
response creation <<<" (and the similar spots around the sections noted at
182-183 and 376-377), call the module's logger (e.g., processLogger or the
existing adapter logger) and log a short message plus only non-sensitive fields
such as err.message and a sanitized error code/identifier, omitting full
err.stack and the raw error object; alternatively gate detailed stack logging
behind a debug flag so stacks are not emitted in normal/shared runtime.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/typescript/ai-groq/package.json`:
- Around line 15-20: Update the package.json "exports" map to add a new
"/adapters/*" subpath so consumers can import tree-shakeable adapters;
specifically extend the existing "exports" object (which currently only has ".")
to include an "/adapters/*" entry that points to the built adapter files (e.g.
"./dist/esm/adapters/*.js" with corresponding types
"./dist/esm/adapters/*.d.ts"), ensuring each adapter file name matches what
exists in the dist (text, embedding, summarize, image) so imports like
"ai-groq/adapters/text" resolve correctly.

In `@packages/typescript/ai-groq/README.md`:
- Around line 47-50: The README example includes a hardcoded API key string when
calling createGroqText; replace that literal with an env-backed placeholder and
update the example to read the key from an environment variable (e.g.,
GROQ_API_KEY) before passing it to createGroqText so users are shown a secure
pattern rather than a secret-like literal. Ensure the updated text clearly shows
the key is loaded from the environment and not hardcoded.

In `@packages/typescript/ai-groq/src/adapters/text.ts`:
- Around line 446-454: The tool message branch currently defaults tool_call_id
to an empty string which hides upstream issues; in the branch that handles
message.role === 'tool' (the returned object containing tool_call_id and
content), validate that message.toolCallId is present and non-empty and do not
emit the tool message if it's missing — either throw a clear Error mentioning
the missing tool_call_id or skip/omit emitting the tool message so you never set
tool_call_id to ''. Update the logic around message.toolCallId (used to populate
tool_call_id) to enforce this check and surface failures instead of silently
defaulting to an empty string.
- Around line 339-346: The mapping for computedFinishReason currently coerces
any non-tool_calls/length finish reasons to 'stop', losing valid values like
'content_filter' and null; update the logic around computedFinishReason
(referencing choice.finish_reason and toolCallsInProgress) so it returns
'tool_calls' when choice.finish_reason === 'tool_calls' ||
toolCallsInProgress.size > 0, 'length' when choice.finish_reason === 'length',
and otherwise preserves choice.finish_reason (including 'content_filter' or
null) so RUN_FINISHED emits the original semantics.

In `@packages/typescript/ai-groq/src/message-types.ts`:
- Around line 313-347: Replace the empty interfaces GroqDocumentMetadata,
GroqTextMetadata, GroqAudioMetadata, and GroqVideoMetadata with explicit type
aliases using Record<string, never> to satisfy the noEmptyInterface rule; locate
the declarations of GroqDocumentMetadata, GroqTextMetadata, GroqAudioMetadata,
and GroqVideoMetadata in message-types.ts and change each empty "interface X {
}" to "type X = Record<string, never>;" so the types remain effectively empty
but comply with Biome's linter.
- Around line 68-73: ChatCompletionNamedToolChoice currently uses a capitalized
Function key and lacks the required discriminator; update the interface so it
matches Groq's required shape: include a literal discriminator property type:
'function' and rename the nested key to lowercase function with { name: string }
(i.e. the object should model {"type":"function","function":{"name":"..."}}),
keeping the symbol ChatCompletionNamedToolChoice as the place to edit.

In `@packages/typescript/ai-groq/src/tools/index.ts`:
- Around line 1-5: The tools module (exports:
convertFunctionToolToAdapterFormat, type FunctionTool,
convertToolsToProviderFormat from the tools index) isn't reachable because
there's no "./tools" subpath export in package.json and the package root
index.ts doesn't re-export it; add a "./tools" entry under the package.json
"exports" map pointing to the compiled tools index, and update the root index.ts
to re-export the tools (e.g., export * from './tools') so consumers can import
`@tanstack/ai-groq/tools` and access convertFunctionToolToAdapterFormat,
FunctionTool, and convertToolsToProviderFormat.

In `@packages/typescript/ai-groq/src/utils/client.ts`:
- Around line 20-26: The current env selection in client.ts binds env to
window.env if that object exists even when it lacks GROQ_API_KEY, preventing
fallback to process.env and causing false "missing key" errors; change the logic
so you first look for GROQ_API_KEY on (globalThis as any).window?.env and use
that value if present, otherwise fall back to process.env.GROQ_API_KEY (or
process.env as the env source) — update the env/key resolution around the env
and key variables so key is derived from window.env.GROQ_API_KEY when defined,
else from process.env.GROQ_API_KEY.

In `@packages/typescript/ai-groq/src/utils/schema-converter.ts`:
- Around line 66-72: The array-handling branch in
makeGroqStructuredOutputCompatible assumes prop.items is a single object and
passing an array (tuple-style JSON Schema) into the object transformation
produces invalid output; update the branches that set properties[propName].items
(and the similar block at the later occurrence) to detect
Array.isArray(prop.items) and, when true, map over prop.items calling
makeGroqStructuredOutputCompatible(item, item.required || []) for each tuple
entry, otherwise keep the existing single-object call for non-tuple schemas
(i.e., preserve the current call makeGroqStructuredOutputCompatible(prop.items,
prop.items.required || []) when items is not an array).
- Around line 57-91: The recursion for object/array props in
makeGroqStructuredOutputCompatible runs before applying optional nullability and
then result.required is incorrectly set to allPropertyNames, which makes
optional fields required; fix by 1) after the existing recursion for prop.type
=== 'object' and prop.type === 'array', apply the optional-nullability patch
using the wasOptional check (i.e., add 'null' into prop.type or prop.type array)
so that object/array props also receive 'null' when optional, and 2) set
result.required = originalRequired (not allPropertyNames) so only originally
required properties remain required; update references in the function to modify
properties[propName] after recursion and use originalRequired for
result.required.

---

Nitpick comments:
In `@packages/typescript/ai-groq/src/adapters/text.ts`:
- Around line 119-123: Replace raw console.error dumps in the chatStream error
handling with sanitized, structured logging: in the block that prints ">>>
chatStream: Fatal error during response creation <<<" (and the similar spots
around the sections noted at 182-183 and 376-377), call the module's logger
(e.g., processLogger or the existing adapter logger) and log a short message
plus only non-sensitive fields such as err.message and a sanitized error
code/identifier, omitting full err.stack and the raw error object; alternatively
gate detailed stack logging behind a debug flag so stacks are not emitted in
normal/shared runtime.

In `@packages/typescript/ai-groq/src/model-meta.ts`:
- Around line 37-305: The model constant identifiers use SCREAMING_SNAKE_CASE
but must follow the repo camelCase convention; rename each constant (e.g.,
LLAMA_3_3_70B_VERSATILE → llama3_3_70bVersatile,
LLAMA_4_MAVERICK_17B_128E_INSTRUCT → llama4Maverick17b128eInstruct,
LLAMA_4_SCOUT_17B_16E_INSTRUCT → llama4Scout17b16eInstruct, LLAMA_GUARD_4_12B →
llamaGuard4_12b, LLAMA_PROMPT_GUARD_2_86M → llamaPromptGuard2_86m,
LLAMA_3_1_8B_INSTANT → llama3_1_8bInstant, LLAMA_PROMPT_GUARD_2_22M →
llamaPromptGuard2_22m, GPT_OSS_120B → gptOss120b, GPT_OSS_SAFEGUARD_20B →
gptOssSafeguard20b, GPT_OSS_20B → gptOss20b, KIMI_K2_INSTRUCT_0905 →
kimiK2Instruct0905, QWEN3_32B → qwen3_32b) keeping the object contents and "as
const satisfies ModelMeta<GroqTextProviderOptions>" intact; then update all
references/imports/usages across the codebase to the new camelCase names
(including any exports or registration maps) to avoid breaking references and
run typechecks to ensure no missed usages.
- Around line 350-362: Change the provider-options mapping to preserve per-model
narrowing by creating a merged options map (e.g. name it ProviderOptionsMap)
that is a Record<string, GroqTextProviderOptions> fallback intersected with a
mapped type over (typeof GROQ_CHAT_MODELS)[number] that assigns model-specific
option types for known models; update GroqChatModelProviderOptionsByName (or
replace it) with that ProviderOptionsMap and change
ResolveProviderOptions<TModel extends string> to use ProviderOptionsMap (TModel
extends keyof ProviderOptionsMap ? ProviderOptionsMap[TModel] :
GroqTextProviderOptions). Edit the types referenced (ResolveProviderOptions,
GroqChatModelProviderOptionsByName, GROQ_CHAT_MODELS, GroqTextProviderOptions)
so known models get specific option subsets while unknown models fall back to
the generic GroqTextProviderOptions.

In `@packages/typescript/ai-groq/src/text/text-provider-options.ts`:
- Around line 221-225: The validateTextProviderOptions function is currently a
no-op; implement fast-fail checks on InternalTextProviderOptions: ensure if
options.include_reasoning is true then options.reasoning_format is
set/non-empty; ensure if options.top_logprobs is provided (>0) then
options.logprobs is also provided/true; ensure options.n (if provided) equals 1
(reject values !== 1); throw a clear Error with descriptive message identifying
the offending field (use the function validateTextProviderOptions to locate the
change) so invalid configs fail fast.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a538dc68-4883-4090-842f-741d7ddeb3ee

📥 Commits

Reviewing files that changed from the base of the PR and between 228e0e3 and cc4a760.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (18)
  • .changeset/free-impalas-doubt.md
  • packages/typescript/ai-groq/README.md
  • packages/typescript/ai-groq/package.json
  • packages/typescript/ai-groq/src/adapters/text.ts
  • packages/typescript/ai-groq/src/index.ts
  • packages/typescript/ai-groq/src/message-types.ts
  • packages/typescript/ai-groq/src/model-meta.ts
  • packages/typescript/ai-groq/src/text/text-provider-options.ts
  • packages/typescript/ai-groq/src/tools/function-tool.ts
  • packages/typescript/ai-groq/src/tools/index.ts
  • packages/typescript/ai-groq/src/tools/tool-converter.ts
  • packages/typescript/ai-groq/src/utils/client.ts
  • packages/typescript/ai-groq/src/utils/index.ts
  • packages/typescript/ai-groq/src/utils/schema-converter.ts
  • packages/typescript/ai-groq/tests/groq-adapter.test.ts
  • packages/typescript/ai-groq/tsconfig.json
  • packages/typescript/ai-groq/vite.config.ts
  • packages/typescript/ai-groq/vitest.config.ts

Comment on lines +15 to +20
"exports": {
".": {
"types": "./dist/esm/index.d.ts",
"import": "./dist/esm/index.js"
}
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add /adapters subpath exports to match tree-shakeable architecture.

Line 15 currently exports only ".", which prevents specialized adapter imports via /adapters/* at the package boundary.

Proposed export map adjustment
   "exports": {
     ".": {
       "types": "./dist/esm/index.d.ts",
       "import": "./dist/esm/index.js"
+    },
+    "./adapters/text": {
+      "types": "./dist/esm/adapters/text.d.ts",
+      "import": "./dist/esm/adapters/text.js"
     }
   },
As per coding guidelines "Use tree-shakeable adapter architecture for provider implementations - export specialized adapters (text, embedding, summarize, image) as separate imports from `/adapters` subpath rather than monolithic adapters".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/package.json` around lines 15 - 20, Update the
package.json "exports" map to add a new "/adapters/*" subpath so consumers can
import tree-shakeable adapters; specifically extend the existing "exports"
object (which currently only has ".") to include an "/adapters/*" entry that
points to the built adapter files (e.g. "./dist/esm/adapters/*.js" with
corresponding types "./dist/esm/adapters/*.d.ts"), ensuring each adapter file
name matches what exists in the dist (text, embedding, summarize, image) so
imports like "ai-groq/adapters/text" resolve correctly.

Comment on lines +47 to +50
import { createGroqText } from '@tanstack/ai-groq'

const adapter = createGroqText('llama-3.3-70b-versatile', 'gsk_api_key')
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Avoid secret-like literal API key examples.

Line 49 shows a hardcoded key-looking string. This pattern is often copy-pasted into source code; prefer env-backed examples to reduce accidental secret exposure.

Suggested doc tweak
 import { createGroqText } from '@tanstack/ai-groq'
 
-const adapter = createGroqText('llama-3.3-70b-versatile', 'gsk_api_key')
+const adapter = createGroqText('llama-3.3-70b-versatile', process.env.GROQ_API_KEY!)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { createGroqText } from '@tanstack/ai-groq'
const adapter = createGroqText('llama-3.3-70b-versatile', 'gsk_api_key')
```
import { createGroqText } from '@tanstack/ai-groq'
const adapter = createGroqText('llama-3.3-70b-versatile', process.env.GROQ_API_KEY!)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/README.md` around lines 47 - 50, The README
example includes a hardcoded API key string when calling createGroqText; replace
that literal with an env-backed placeholder and update the example to read the
key from an environment variable (e.g., GROQ_API_KEY) before passing it to
createGroqText so users are shown a secure pattern rather than a secret-like
literal. Ensure the updated text clearly shows the key is loaded from the
environment and not hardcoded.

Comment on lines +446 to +454
if (message.role === 'tool') {
return {
role: 'tool',
tool_call_id: message.toolCallId || '',
content:
typeof message.content === 'string'
? message.content
: JSON.stringify(message.content),
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Do not emit tool messages with an empty tool_call_id.

Defaulting tool_call_id to '' hides upstream data issues and can break tool-response correlation.

Suggested fix
     if (message.role === 'tool') {
+      if (!message.toolCallId) {
+        throw new Error('Tool message requires a non-empty toolCallId')
+      }
       return {
         role: 'tool',
-        tool_call_id: message.toolCallId || '',
+        tool_call_id: message.toolCallId,
         content:
           typeof message.content === 'string'
             ? message.content
             : JSON.stringify(message.content),
       }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (message.role === 'tool') {
return {
role: 'tool',
tool_call_id: message.toolCallId || '',
content:
typeof message.content === 'string'
? message.content
: JSON.stringify(message.content),
}
if (message.role === 'tool') {
if (!message.toolCallId) {
throw new Error('Tool message requires a non-empty toolCallId')
}
return {
role: 'tool',
tool_call_id: message.toolCallId,
content:
typeof message.content === 'string'
? message.content
: JSON.stringify(message.content),
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/src/adapters/text.ts` around lines 446 - 454, The
tool message branch currently defaults tool_call_id to an empty string which
hides upstream issues; in the branch that handles message.role === 'tool' (the
returned object containing tool_call_id and content), validate that
message.toolCallId is present and non-empty and do not emit the tool message if
it's missing — either throw a clear Error mentioning the missing tool_call_id or
skip/omit emitting the tool message so you never set tool_call_id to ''. Update
the logic around message.toolCallId (used to populate tool_call_id) to enforce
this check and surface failures instead of silently defaulting to an empty
string.

Comment on lines +68 to +73
export interface ChatCompletionNamedToolChoice {
Function: {
/** The name of the function to call. */
name: string
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cd packages/typescript/ai-groq && head -n 350 src/message-types.ts | tail -n +60

Repository: TanStack/ai

Length of output: 8253


🌐 Web query:

Groq Chat Completions API tool_choice parameter JSON schema specification

💡 Result:

Groq’s Chat Completions request body defines tool_choice as string | object | null. It controls whether the model calls tools, and can be one of:

  • "none", "auto", or "required" (string forms)
  • an object forcing a specific tool: {"type":"function","function":{"name":"my_function"}}
    (console.groq.com)

A concise JSON Schema you can use to validate the tool_choice parameter:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Groq Chat Completions tool_choice",
  "description": "Controls which (if any) tool is called by the model.",
  "oneOf": [
    { "type": "null" },
    {
      "type": "string",
      "enum": ["none", "auto", "required"]
    },
    {
      "type": "object",
      "additionalProperties": false,
      "required": ["type", "function"],
      "properties": {
        "type": { "const": "function" },
        "function": {
          "type": "object",
          "additionalProperties": false,
          "required": ["name"],
          "properties": {
            "name": { "type": "string", "minLength": 1 }
          }
        }
      }
    }
  ]
}

Note: Groq also documents the older, deprecated function_call parameter (superseded by tool_choice), which used "none", "auto", or an object like {"name":"my_function"}. (console.groq.com)

Citations:


🏁 Script executed:

cd packages/typescript/ai-groq && sed -n '105,120p' src/message-types.ts

Repository: TanStack/ai

Length of output: 617


ChatCompletionNamedToolChoice violates Groq API specification for forced tool selection.

The type uses capitalized Function instead of lowercase function and omits the required type: 'function' discriminator. Groq's Chat Completions API specifies tool forcing via {"type":"function","function":{"name":"..."}}. The current implementation will generate invalid payloads.

Required fix
 export interface ChatCompletionNamedToolChoice {
-  Function: {
+  type: 'function'
+  function: {
     /** The name of the function to call. */
     name: string
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/src/message-types.ts` around lines 68 - 73,
ChatCompletionNamedToolChoice currently uses a capitalized Function key and
lacks the required discriminator; update the interface so it matches Groq's
required shape: include a literal discriminator property type: 'function' and
rename the nested key to lowercase function with { name: string } (i.e. the
object should model {"type":"function","function":{"name":"..."}}), keeping the
symbol ChatCompletionNamedToolChoice as the place to edit.

Comment on lines +313 to +347
export interface GroqDocumentMetadata { }

/**
* Metadata for Groq text content parts.
* Currently no specific metadata options for text in Groq.
*/
export interface GroqTextMetadata { }

/**
* Metadata for Groq image content parts.
* Controls how the model processes and analyzes images.
*/
export interface GroqImageMetadata {
/**
* Specifies the detail level of the image.
* - 'auto': Let the model decide based on image size and content
* - 'low': Use low resolution processing (faster, cheaper, less detail)
* - 'high': Use high resolution processing (slower, more expensive, more detail)
*
* @default 'auto'
*/
detail?: 'auto' | 'low' | 'high'
}

/**
* Metadata for Groq audio content parts.
* Note: Audio support in Groq is limited; check current API capabilities.
*/
export interface GroqAudioMetadata { }

/**
* Metadata for Groq video content parts.
* Note: Groq does not currently support video input.
*/
export interface GroqVideoMetadata { }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if the file exists and examine the relevant lines
if [ -f "packages/typescript/ai-groq/src/message-types.ts" ]; then
  echo "=== File exists, checking lines 313-347 ==="
  sed -n '313,347p' packages/typescript/ai-groq/src/message-types.ts
else
  echo "File not found at packages/typescript/ai-groq/src/message-types.ts"
fi

# Search for all empty interface declarations in the file
echo ""
echo "=== All empty metadata interfaces ==="
rg -n 'export interface Groq\w*Metadata\s*\{\s*\}' packages/typescript/ai-groq/src/message-types.ts

# Check for Biome configuration files
echo ""
echo "=== Looking for Biome configuration ==="
fd -t f '(biome\.json|\.biomrc\.json|biome\.jsonc)' .

Repository: TanStack/ai

Length of output: 1357


🏁 Script executed:

#!/bin/bash
# Check the Biome configuration for noEmptyInterface rule
echo "=== Biome configuration (if found) ==="
for config_file in biome.json biome.jsonc .biomrc.json; do
  if [ -f "$config_file" ]; then
    echo "Found: $config_file"
    cat "$config_file" | head -100
  fi
done

# Also check package.json for biome configuration
if [ -f "package.json" ]; then
  echo ""
  echo "=== Checking package.json for biome config ==="
  cat package.json | jq '.biome // empty' 2>/dev/null || echo "No biome config in package.json"
fi

Repository: TanStack/ai

Length of output: 1933


🏁 Script executed:

#!/bin/bash
# Verify the exact interfaces mentioned and check for any other empty interfaces in the file
echo "=== Full content of message-types.ts to understand context ==="
wc -l packages/typescript/ai-groq/src/message-types.ts

echo ""
echo "=== Lines 300-350 for context ==="
sed -n '300,350p' packages/typescript/ai-groq/src/message-types.ts

Repository: TanStack/ai

Length of output: 1622


🏁 Script executed:

#!/bin/bash
# Check usages of these empty metadata interfaces
echo "=== Searching for usages of empty metadata interfaces ==="
rg -n 'GroqDocumentMetadata|GroqTextMetadata|GroqAudioMetadata|GroqVideoMetadata' packages/typescript/ai-groq/src/ --type ts --type tsx

# Also check the full packages directory for cross-package usages
echo ""
echo "=== Checking for usages in entire packages directory ==="
rg -c 'GroqDocumentMetadata|GroqTextMetadata|GroqAudioMetadata|GroqVideoMetadata' packages/ --type ts --type tsx | head -20

Repository: TanStack/ai

Length of output: 243


🏁 Script executed:

#!/bin/bash
# Verify that Record<string, never> is correct and check TypeScript/Biome best practices
echo "=== Checking if Record<string, never> pattern is used elsewhere in codebase ==="
rg -n 'Record<string, never>' packages/ --type ts --type tsx | head -10

# Also check for similar empty type patterns
echo ""
echo "=== Checking for other empty object type patterns ==="
rg -n 'type.*= Record<string, never>|type.*= \{\}' packages/typescript/ --type ts --type tsx | head -15

Repository: TanStack/ai

Length of output: 262


🏁 Script executed:

#!/bin/bash
# Look at imports and exports around the metadata interfaces to understand their usage patterns
echo "=== Context around the metadata interface exports (lines 310-355) ==="
sed -n '310,355p' packages/typescript/ai-groq/src/message-types.ts

Repository: TanStack/ai

Length of output: 1409


Replace empty metadata interfaces with Record<string, never> to satisfy Biome's noEmptyInterface rule.

Biome's linter has the noEmptyInterface rule enabled (via recommended preset in biome.json). The following empty interfaces should be replaced with explicit type aliases:

Suggested fix
-export interface GroqDocumentMetadata { }
+export type GroqDocumentMetadata = Record<string, never>
@@
-export interface GroqTextMetadata { }
+export type GroqTextMetadata = Record<string, never>
@@
-export interface GroqAudioMetadata { }
+export type GroqAudioMetadata = Record<string, never>
@@
-export interface GroqVideoMetadata { }
+export type GroqVideoMetadata = Record<string, never>
🧰 Tools
🪛 Biome (2.4.4)

[error] 313-313: An empty interface is equivalent to {}.

(lint/suspicious/noEmptyInterface)


[error] 319-319: An empty interface is equivalent to {}.

(lint/suspicious/noEmptyInterface)


[error] 341-341: An empty interface is equivalent to {}.

(lint/suspicious/noEmptyInterface)


[error] 347-347: An empty interface is equivalent to {}.

(lint/suspicious/noEmptyInterface)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/src/message-types.ts` around lines 313 - 347,
Replace the empty interfaces GroqDocumentMetadata, GroqTextMetadata,
GroqAudioMetadata, and GroqVideoMetadata with explicit type aliases using
Record<string, never> to satisfy the noEmptyInterface rule; locate the
declarations of GroqDocumentMetadata, GroqTextMetadata, GroqAudioMetadata, and
GroqVideoMetadata in message-types.ts and change each empty "interface X { }" to
"type X = Record<string, never>;" so the types remain effectively empty but
comply with Biome's linter.

Comment on lines +1 to +5
export {
convertFunctionToolToAdapterFormat,
type FunctionTool,
} from './function-tool'
export { convertToolsToProviderFormat } from './tool-converter'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check the exports configuration in package.json
echo "=== Package.json exports for ai-groq ==="
jq '.exports' packages/typescript/ai-groq/package.json

# Also check if ./tools is specifically exported
echo ""
echo "=== Checking for tools export ==="
jq '.exports | has("./tools") or (.exports | to_entries[] | select(.value | type == "string" or (.import or .require)) | .key)' packages/typescript/ai-groq/package.json 2>/dev/null || echo "Checking exports structure..."

# Get full exports structure for clarity
echo ""
echo "=== Full exports structure ==="
jq -r '.exports | to_entries[] | "\(.key): \(.value)"' packages/typescript/ai-groq/package.json

Repository: TanStack/ai

Length of output: 351


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check if root index.ts re-exports the tools
echo "=== Root index.ts content ==="
cat -n packages/typescript/ai-groq/src/index.ts | head -50

# Also check the build output to confirm what's available
echo ""
echo "=== Built tools index structure ==="
find packages/typescript/ai-groq/dist -name "*tools*" -o -name "*function-tool*" -o -name "*tool-converter*" 2>/dev/null | head -20

Repository: TanStack/ai

Length of output: 1112


Add ./tools subpath export to package.json and update root index.ts to re-export tools utilities.

The tools are exported from packages/typescript/ai-groq/src/tools/index.ts but remain unreachable to consumers—there is no ./tools entry in the package.json exports, and the root index.ts does not re-export them. This violates the coding guideline to export tree-shakeable adapters with clear subpath exports in package.json. Add the export entry and update root exports accordingly to make tools accessible as @tanstack/ai-groq/tools.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/src/tools/index.ts` around lines 1 - 5, The tools
module (exports: convertFunctionToolToAdapterFormat, type FunctionTool,
convertToolsToProviderFormat from the tools index) isn't reachable because
there's no "./tools" subpath export in package.json and the package root
index.ts doesn't re-export it; add a "./tools" entry under the package.json
"exports" map pointing to the compiled tools index, and update the root index.ts
to re-export the tools (e.g., export * from './tools') so consumers can import
`@tanstack/ai-groq/tools` and access convertFunctionToolToAdapterFormat,
FunctionTool, and convertToolsToProviderFormat.

Comment on lines +20 to +26
const env =
typeof globalThis !== 'undefined' && (globalThis as any).window?.env
? (globalThis as any).window.env
: typeof process !== 'undefined'
? process.env
: undefined
const key = env?.GROQ_API_KEY
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix API key source fallback logic in hybrid runtimes.

Line 21 chooses window.env as a whole object; if it exists without GROQ_API_KEY, Line 26 never falls back to process.env, causing false “missing key” errors.

Proposed fix
 export function getGroqApiKeyFromEnv(): string {
-  const env =
-    typeof globalThis !== 'undefined' && (globalThis as any).window?.env
-      ? (globalThis as any).window.env
-      : typeof process !== 'undefined'
-        ? process.env
-        : undefined
-  const key = env?.GROQ_API_KEY
+  const browserKey =
+    typeof globalThis !== 'undefined'
+      ? (globalThis as { window?: { env?: Record<string, string | undefined> } }).window?.env
+          ?.GROQ_API_KEY
+      : undefined
+  const nodeKey = typeof process !== 'undefined' ? process.env?.GROQ_API_KEY : undefined
+  const key = browserKey ?? nodeKey
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/src/utils/client.ts` around lines 20 - 26, The
current env selection in client.ts binds env to window.env if that object exists
even when it lacks GROQ_API_KEY, preventing fallback to process.env and causing
false "missing key" errors; change the logic so you first look for GROQ_API_KEY
on (globalThis as any).window?.env and use that value if present, otherwise fall
back to process.env.GROQ_API_KEY (or process.env as the env source) — update the
env/key resolution around the env and key variables so key is derived from
window.env.GROQ_API_KEY when defined, else from process.env.GROQ_API_KEY.

Comment on lines +57 to +91
for (const propName of allPropertyNames) {
const prop = properties[propName]
const wasOptional = !originalRequired.includes(propName)

if (prop.type === 'object' && prop.properties) {
properties[propName] = makeGroqStructuredOutputCompatible(
prop,
prop.required || [],
)
} else if (prop.type === 'array' && prop.items) {
properties[propName] = {
...prop,
items: makeGroqStructuredOutputCompatible(
prop.items,
prop.items.required || [],
),
}
} else if (wasOptional) {
if (prop.type && !Array.isArray(prop.type)) {
properties[propName] = {
...prop,
type: [prop.type, 'null'],
}
} else if (Array.isArray(prop.type) && !prop.type.includes('null')) {
properties[propName] = {
...prop,
type: [...prop.type, 'null'],
}
}
}
}

result.properties = properties
result.required = allPropertyNames
result.additionalProperties = false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Optional object/array properties lose optional semantics after transformation.

Lines 61 and 66 recurse before optional handling, so optional object/array fields never get 'null' added. Then Line 90 makes all fields required, effectively making those optional fields required.

Proposed fix (apply nullability after recursion for all optional properties)
         for (const propName of allPropertyNames) {
             const prop = properties[propName]
             const wasOptional = !originalRequired.includes(propName)
+            let transformedProp = prop
 
             if (prop.type === 'object' && prop.properties) {
-                properties[propName] = makeGroqStructuredOutputCompatible(
+                transformedProp = makeGroqStructuredOutputCompatible(
                     prop,
                     prop.required || [],
                 )
             } else if (prop.type === 'array' && prop.items) {
-                properties[propName] = {
+                transformedProp = {
                     ...prop,
                     items: makeGroqStructuredOutputCompatible(
                         prop.items,
                         prop.items.required || [],
                     ),
                 }
-            } else if (wasOptional) {
-                if (prop.type && !Array.isArray(prop.type)) {
-                    properties[propName] = {
-                        ...prop,
-                        type: [prop.type, 'null'],
-                    }
-                } else if (Array.isArray(prop.type) && !prop.type.includes('null')) {
-                    properties[propName] = {
-                        ...prop,
-                        type: [...prop.type, 'null'],
-                    }
-                }
             }
+
+            if (wasOptional) {
+                if (transformedProp.type && !Array.isArray(transformedProp.type)) {
+                    transformedProp = { ...transformedProp, type: [transformedProp.type, 'null'] }
+                } else if (Array.isArray(transformedProp.type) && !transformedProp.type.includes('null')) {
+                    transformedProp = { ...transformedProp, type: [...transformedProp.type, 'null'] }
+                }
+            }
+            properties[propName] = transformedProp
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/src/utils/schema-converter.ts` around lines 57 -
91, The recursion for object/array props in makeGroqStructuredOutputCompatible
runs before applying optional nullability and then result.required is
incorrectly set to allPropertyNames, which makes optional fields required; fix
by 1) after the existing recursion for prop.type === 'object' and prop.type ===
'array', apply the optional-nullability patch using the wasOptional check (i.e.,
add 'null' into prop.type or prop.type array) so that object/array props also
receive 'null' when optional, and 2) set result.required = originalRequired (not
allPropertyNames) so only originally required properties remain required; update
references in the function to modify properties[propName] after recursion and
use originalRequired for result.required.

Comment on lines +66 to +72
} else if (prop.type === 'array' && prop.items) {
properties[propName] = {
...prop,
items: makeGroqStructuredOutputCompatible(
prop.items,
prop.items.required || [],
),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Handle tuple-style array schemas (items: JSONSchema[]) explicitly.

Line 70 and Line 96 assume items is a single schema object. When items is an array (tuple schema), this logic passes an array into object-based transformation and can produce invalid output.

Proposed fix for tuple `items` support
             } else if (prop.type === 'array' && prop.items) {
                 transformedProp = {
                     ...prop,
-                    items: makeGroqStructuredOutputCompatible(
-                        prop.items,
-                        prop.items.required || [],
-                    ),
+                    items: Array.isArray(prop.items)
+                        ? prop.items.map((item) =>
+                              makeGroqStructuredOutputCompatible(item, item.required || []),
+                          )
+                        : makeGroqStructuredOutputCompatible(
+                              prop.items,
+                              prop.items.required || [],
+                          ),
                 }
             }
@@
     if (result.type === 'array' && result.items) {
-        result.items = makeGroqStructuredOutputCompatible(
-            result.items,
-            result.items.required || [],
-        )
+        result.items = Array.isArray(result.items)
+            ? result.items.map((item) =>
+                  makeGroqStructuredOutputCompatible(item, item.required || []),
+              )
+            : makeGroqStructuredOutputCompatible(result.items, result.items.required || [])
     }

Also applies to: 94-98

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/typescript/ai-groq/src/utils/schema-converter.ts` around lines 66 -
72, The array-handling branch in makeGroqStructuredOutputCompatible assumes
prop.items is a single object and passing an array (tuple-style JSON Schema)
into the object transformation produces invalid output; update the branches that
set properties[propName].items (and the similar block at the later occurrence)
to detect Array.isArray(prop.items) and, when true, map over prop.items calling
makeGroqStructuredOutputCompatible(item, item.required || []) for each tuple
entry, otherwise keep the existing single-object call for non-tuple schemas
(i.e., preserve the current call makeGroqStructuredOutputCompatible(prop.items,
prop.items.required || []) when items is not an array).

@nx-cloud
Copy link

nx-cloud bot commented Mar 6, 2026

View your CI Pipeline Execution ↗ for commit b80b693

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... ✅ Succeeded 3m 33s View ↗
nx run-many --targets=build --exclude=examples/** ✅ Succeeded 1m 22s View ↗

☁️ Nx Cloud last updated this comment at 2026-03-06 14:55:17 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 6, 2026

Open in StackBlitz

@tanstack/ai

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai@332

@tanstack/ai-anthropic

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-anthropic@332

@tanstack/ai-client

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-client@332

@tanstack/ai-devtools-core

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-devtools-core@332

@tanstack/ai-fal

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-fal@332

@tanstack/ai-gemini

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-gemini@332

@tanstack/ai-grok

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-grok@332

@tanstack/ai-groq

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-groq@332

@tanstack/ai-ollama

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-ollama@332

@tanstack/ai-openai

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-openai@332

@tanstack/ai-openrouter

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-openrouter@332

@tanstack/ai-preact

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-preact@332

@tanstack/ai-react

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-react@332

@tanstack/ai-react-ui

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-react-ui@332

@tanstack/ai-solid

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-solid@332

@tanstack/ai-solid-ui

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-solid-ui@332

@tanstack/ai-svelte

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-svelte@332

@tanstack/ai-vue

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-vue@332

@tanstack/ai-vue-ui

npm i https://pkg.pr.new/TanStack/ai/@tanstack/ai-vue-ui@332

@tanstack/preact-ai-devtools

npm i https://pkg.pr.new/TanStack/ai/@tanstack/preact-ai-devtools@332

@tanstack/react-ai-devtools

npm i https://pkg.pr.new/TanStack/ai/@tanstack/react-ai-devtools@332

@tanstack/solid-ai-devtools

npm i https://pkg.pr.new/TanStack/ai/@tanstack/solid-ai-devtools@332

commit: 4f90518

@AlemTuzlak AlemTuzlak merged commit ee36187 into TanStack:main Mar 6, 2026
3 of 4 checks passed
@github-actions github-actions bot mentioned this pull request Mar 6, 2026
@dhamivibez dhamivibez deleted the adapter/groq branch March 6, 2026 17:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants