Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/free-impalas-doubt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/ai-groq': minor
---

Adds a new @tanstack/ai-groq package(minor release), a Groq AI adapter for TanStack AI.
1 change: 1 addition & 0 deletions examples/ts-react-chat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@tanstack/ai-client": "workspace:*",
"@tanstack/ai-gemini": "workspace:*",
"@tanstack/ai-grok": "workspace:*",
"@tanstack/ai-groq": "workspace:*",
"@tanstack/ai-ollama": "workspace:*",
"@tanstack/ai-openai": "workspace:*",
"@tanstack/ai-openrouter": "workspace:*",
Expand Down
18 changes: 18 additions & 0 deletions examples/ts-react-chat/src/lib/model-selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export type Provider =
| 'gemini'
| 'ollama'
| 'grok'
| 'groq'
| 'openrouter'

export interface ModelOption {
Expand Down Expand Up @@ -91,6 +92,23 @@ export const MODEL_OPTIONS: Array<ModelOption> = [
label: 'Ollama - SmolLM',
},

// Groq
{
provider: 'groq',
model: 'llama-3.3-70b-versatile',
label: 'Groq - Llama 3.3 70B',
},
{
provider: 'groq',
model: 'meta-llama/llama-4-maverick-17b-128e-instruct',
label: 'Groq - Llama 4 Maverick',
},
{
provider: 'groq',
model: 'meta-llama/llama-4-scout-17b-16e-instruct',
label: 'Groq - Llama 4 Scout',
},

// Grok
{
provider: 'grok',
Expand Down
9 changes: 9 additions & 0 deletions examples/ts-react-chat/src/routes/api.tanchat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { anthropicText } from '@tanstack/ai-anthropic'
import { geminiText } from '@tanstack/ai-gemini'
import { openRouterText } from '@tanstack/ai-openrouter'
import { grokText } from '@tanstack/ai-grok'
import { groqText } from '@tanstack/ai-groq'
import type { AnyTextAdapter } from '@tanstack/ai'
import {
addToCartToolDef,
Expand All @@ -26,6 +27,7 @@ type Provider =
| 'gemini'
| 'ollama'
| 'grok'
| 'groq'
| 'openrouter'

const SYSTEM_PROMPT = `You are a helpful assistant for a guitar store.
Expand Down Expand Up @@ -131,6 +133,13 @@ export const Route = createFileRoute('/api/tanchat')({
adapter: grokText((model || 'grok-3') as 'grok-3'),
modelOptions: {},
}),
groq: () =>
createChatOptions({
adapter: groqText(
(model ||
'llama-3.3-70b-versatile') as 'llama-3.3-70b-versatile',
),
}),
ollama: () =>
createChatOptions({
adapter: ollamaText((model || 'gpt-oss:120b') as 'gpt-oss:120b'),
Expand Down
38 changes: 25 additions & 13 deletions examples/ts-react-chat/src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -264,19 +264,25 @@ function ChatPage() {
[selectedModel.provider, selectedModel.model],
)

const { messages, sendMessage, isLoading, addToolApprovalResponse, stop } =
useChat({
connection: fetchServerSentEvents('/api/tanchat'),
tools,
body,
onCustomEvent: (eventType, data, context) => {
console.log(
`[CustomEvent] ${eventType}`,
data,
context.toolCallId ? `(tool call: ${context.toolCallId})` : '',
)
},
})
const {
messages,
sendMessage,
isLoading,
error,
addToolApprovalResponse,
stop,
} = useChat({
connection: fetchServerSentEvents('/api/tanchat'),
tools,
body,
onCustomEvent: (eventType, data, context) => {
console.log(
`[CustomEvent] ${eventType}`,
data,
context.toolCallId ? `(tool call: ${context.toolCallId})` : '',
)
},
})
const [input, setInput] = useState('')

/**
Expand Down Expand Up @@ -415,6 +421,12 @@ function ChatPage() {
addToolApprovalResponse={addToolApprovalResponse}
/>

{error && (
<div className="mx-4 mt-2 p-3 bg-red-500/10 border border-red-500/30 rounded-lg text-red-400 text-sm">
{error.message}
</div>
)}

<ChatInputArea>
<div className="space-y-3">
{isLoading && (
Expand Down
91 changes: 91 additions & 0 deletions packages/typescript/ai-groq/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# @tanstack/ai-groq

Groq adapter for TanStack AI

## Installation

```bash
npm install @tanstack/ai-groq
# or
pnpm add @tanstack/ai-groq
# or
yarn add @tanstack/ai-groq
```

## Setup

Get your API key from [Groq Console](https://console.groq.com) and set it as an environment variable:

```bash
export GROQ_API_KEY="gsk_..."
```

## Usage

### Text/Chat Adapter

```typescript
import { groqText } from '@tanstack/ai-groq'
import { generate } from '@tanstack/ai'

const adapter = groqText('llama-3.3-70b-versatile')

const result = await generate({
adapter,
model: 'llama-3.3-70b-versatile',
messages: [
{ role: 'user', content: 'Explain quantum computing in simple terms' },
],
})

console.log(result.text)
```

### With Explicit API Key

```typescript
import { createGroqText } from '@tanstack/ai-groq'

const adapter = createGroqText('llama-3.3-70b-versatile', 'gsk_api_key')
```
Comment on lines +47 to +50
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.


## Supported Models

### Chat Models

- `llama-3.3-70b-versatile` - Meta Llama 3.3 70B (131k context)
- `llama-3.1-8b-instant` - Meta Llama 3.1 8B (131k context)
- `meta-llama/llama-4-maverick-17b-128e-instruct` - Meta Llama 4 Maverick (vision)
- `meta-llama/llama-4-scout-17b-16e-instruct` - Meta Llama 4 Scout
- `meta-llama/llama-guard-4-12b` - Meta Llama Guard 4 (content moderation, vision)
- `meta-llama/llama-prompt-guard-2-86m` - Meta Llama Prompt Guard (content moderation)
- `meta-llama/llama-prompt-guard-2-22m` - Meta Llama Prompt Guard (content moderation)
- `openai/gpt-oss-120b` - GPT OSS 120B (reasoning, tools, search)
- `openai/gpt-oss-20b` - GPT OSS 20B (reasoning, search)
- `openai/gpt-oss-safeguard-20b` - GPT OSS Safeguard 20B (content moderation, reasoning)
- `moonshotai/kimi-k2-instruct-0905` - Kimi K2 Instruct (262k context)
- `qwen/qwen3-32b` - Qwen3 32B (reasoning, tools)

## Features

- ✅ Streaming chat completions
- ✅ Structured output (JSON Schema)
- ✅ Function/tool calling
- ✅ Multimodal input (text + images for vision models)
- ❌ Embeddings (not supported by Groq)
- ❌ Image generation (not supported by Groq)

## Tree-Shakeable Adapters

This package uses tree-shakeable adapters, so you only import what you need:

```typescript
// Only imports text adapter
import { groqText } from '@tanstack/ai-groq'
```

This keeps your bundle size small!

## License

MIT
52 changes: 52 additions & 0 deletions packages/typescript/ai-groq/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"name": "@tanstack/ai-groq",
"version": "0.0.0",
"type": "module",
"description": "Groq adapter for TanStack AI",
"author": "",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/TanStack/ai.git",
"directory": "packages/typescript/ai-groq"
},
"module": "./dist/esm/index.js",
"types": "./dist/esm/index.d.ts",
"exports": {
".": {
"types": "./dist/esm/index.d.ts",
"import": "./dist/esm/index.js"
}
},
Comment on lines +15 to +20
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.

"files": [
"dist",
"src"
],
"scripts": {
"build": "vite build",
"clean": "premove ./build ./dist",
"lint:fix": "eslint ./src --fix",
"test:build": "publint --strict",
"test:eslint": "eslint ./src",
"test:lib": "vitest run",
"test:lib:dev": "pnpm test:lib --watch",
"test:types": "tsc"
},
"keywords": [
"ai",
"groq",
"tanstack",
"adapter"
],
"devDependencies": {
"@vitest/coverage-v8": "4.0.14",
"vite": "^7.2.7"
},
"peerDependencies": {
"@tanstack/ai": "workspace:^",
"zod": "^4.0.0"
},
"dependencies": {
"groq-sdk": "^0.37.0"
}
}
Loading
Loading