feat: complete Groq provider integration and add Kimi K2 model (#978)

* feat: complete Groq provider integration and add Kimi K2 model

- Add missing getRequiredApiKeyName() method to GroqProvider class
- Register GroqProvider in ai-services-unified.js PROVIDERS object
- Add Groq API key handling to config-manager.js (isApiKeySet and getMcpApiKeyStatus)
- Add GROQ_API_KEY to env.example with format hint
- Add moonshotai/kimi-k2-instruct model to Groq provider ($1/$3 per 1M tokens, 16k max)
- Fix import sorting for linting compliance
- Add GroqProvider mock to ai-services-unified tests

Fixes missing implementation pieces that prevented Groq provider from working.

* chore: improve changeset

---------

Co-authored-by: Ben Vargas <ben@example.com>
Co-authored-by: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com>
This commit is contained in:
Ben Vargas
2025-07-16 06:42:12 -06:00
committed by Ralph Khreish
parent 624922ca59
commit 58a301c380
7 changed files with 74 additions and 31 deletions

View File

@@ -0,0 +1,10 @@
---
"task-master-ai": minor
---
Complete Groq provider integration and add MoonshotAI Kimi K2 model support
- Fixed Groq provider registration
- Added Groq API key validation
- Added GROQ_API_KEY to .env.example
- Added moonshotai/kimi-k2-instruct model with $1/$3 per 1M token pricing and 16k max output

View File

@@ -5,6 +5,7 @@ OPENAI_API_KEY="your_openai_api_key_here" # Optional, for OpenAI/Ope
GOOGLE_API_KEY="your_google_api_key_here" # Optional, for Google Gemini models. GOOGLE_API_KEY="your_google_api_key_here" # Optional, for Google Gemini models.
MISTRAL_API_KEY="your_mistral_key_here" # Optional, for Mistral AI models. MISTRAL_API_KEY="your_mistral_key_here" # Optional, for Mistral AI models.
XAI_API_KEY="YOUR_XAI_KEY_HERE" # Optional, for xAI AI models. XAI_API_KEY="YOUR_XAI_KEY_HERE" # Optional, for xAI AI models.
GROQ_API_KEY="your_groq_api_key_here" # Optional, for Groq models. Format: gsk_...
AZURE_OPENAI_API_KEY="your_azure_key_here" # Optional, for Azure OpenAI models (requires endpoint in .taskmaster/config.json). AZURE_OPENAI_API_KEY="your_azure_key_here" # Optional, for Azure OpenAI models (requires endpoint in .taskmaster/config.json).
OLLAMA_API_KEY="your_ollama_api_key_here" # Optional: For remote Ollama servers that require authentication. OLLAMA_API_KEY="your_ollama_api_key_here" # Optional: For remote Ollama servers that require authentication.
GITHUB_API_KEY="your_github_api_key_here" # Optional: For GitHub import/export features. Format: ghp_... or github_pat_... GITHUB_API_KEY="your_github_api_key_here" # Optional: For GitHub import/export features. Format: ghp_... or github_pat_...

View File

@@ -8,47 +8,48 @@
// --- Core Dependencies --- // --- Core Dependencies ---
import { import {
getMainProvider, MODEL_MAP,
getMainModelId, getAzureBaseURL,
getResearchProvider, getBaseUrlForRole,
getResearchModelId, getBedrockBaseURL,
getFallbackProvider, getDebugFlag,
getFallbackModelId, getFallbackModelId,
getFallbackProvider,
getMainModelId,
getMainProvider,
getOllamaBaseURL,
getParametersForRole, getParametersForRole,
getResearchModelId,
getResearchProvider,
getResponseLanguage, getResponseLanguage,
getUserId, getUserId,
MODEL_MAP,
getDebugFlag,
getBaseUrlForRole,
isApiKeySet,
getOllamaBaseURL,
getAzureBaseURL,
getBedrockBaseURL,
getVertexProjectId,
getVertexLocation, getVertexLocation,
getVertexProjectId,
isApiKeySet,
providersWithoutApiKeys providersWithoutApiKeys
} from './config-manager.js'; } from './config-manager.js';
import { import {
log,
findProjectRoot, findProjectRoot,
resolveEnvVariable, getCurrentTag,
getCurrentTag log,
resolveEnvVariable
} from './utils.js'; } from './utils.js';
// Import provider classes // Import provider classes
import { import {
AnthropicAIProvider, AnthropicAIProvider,
PerplexityAIProvider,
GoogleAIProvider,
OpenAIProvider,
XAIProvider,
OpenRouterAIProvider,
OllamaAIProvider,
BedrockAIProvider,
AzureProvider, AzureProvider,
VertexAIProvider, BedrockAIProvider,
ClaudeCodeProvider, ClaudeCodeProvider,
GeminiCliProvider GeminiCliProvider,
GoogleAIProvider,
GroqProvider,
OllamaAIProvider,
OpenAIProvider,
OpenRouterAIProvider,
PerplexityAIProvider,
VertexAIProvider,
XAIProvider
} from '../../src/ai-providers/index.js'; } from '../../src/ai-providers/index.js';
// Import the provider registry // Import the provider registry
@@ -61,6 +62,7 @@ const PROVIDERS = {
google: new GoogleAIProvider(), google: new GoogleAIProvider(),
openai: new OpenAIProvider(), openai: new OpenAIProvider(),
xai: new XAIProvider(), xai: new XAIProvider(),
groq: new GroqProvider(),
openrouter: new OpenRouterAIProvider(), openrouter: new OpenRouterAIProvider(),
ollama: new OllamaAIProvider(), ollama: new OllamaAIProvider(),
bedrock: new BedrockAIProvider(), bedrock: new BedrockAIProvider(),

View File

@@ -1,21 +1,21 @@
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import { fileURLToPath } from 'url';
import chalk from 'chalk'; import chalk from 'chalk';
import { z } from 'zod'; import { z } from 'zod';
import { fileURLToPath } from 'url'; import { AI_COMMAND_NAMES } from '../../src/constants/commands.js';
import { log, findProjectRoot, resolveEnvVariable, isEmpty } from './utils.js';
import { import {
LEGACY_CONFIG_FILE, LEGACY_CONFIG_FILE,
TASKMASTER_DIR TASKMASTER_DIR
} from '../../src/constants/paths.js'; } from '../../src/constants/paths.js';
import { findConfigPath } from '../../src/utils/path-utils.js';
import { import {
VALIDATED_PROVIDERS, ALL_PROVIDERS,
CUSTOM_PROVIDERS, CUSTOM_PROVIDERS,
CUSTOM_PROVIDERS_ARRAY, CUSTOM_PROVIDERS_ARRAY,
ALL_PROVIDERS VALIDATED_PROVIDERS
} from '../../src/constants/providers.js'; } from '../../src/constants/providers.js';
import { AI_COMMAND_NAMES } from '../../src/constants/commands.js'; import { findConfigPath } from '../../src/utils/path-utils.js';
import { findProjectRoot, isEmpty, log, resolveEnvVariable } from './utils.js';
// Calculate __dirname in ESM // Calculate __dirname in ESM
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
@@ -641,6 +641,7 @@ function isApiKeySet(providerName, session = null, projectRoot = null) {
azure: 'AZURE_OPENAI_API_KEY', azure: 'AZURE_OPENAI_API_KEY',
openrouter: 'OPENROUTER_API_KEY', openrouter: 'OPENROUTER_API_KEY',
xai: 'XAI_API_KEY', xai: 'XAI_API_KEY',
groq: 'GROQ_API_KEY',
vertex: 'GOOGLE_API_KEY', // Vertex uses the same key as Google vertex: 'GOOGLE_API_KEY', // Vertex uses the same key as Google
'claude-code': 'CLAUDE_CODE_API_KEY', // Not actually used, but included for consistency 'claude-code': 'CLAUDE_CODE_API_KEY', // Not actually used, but included for consistency
bedrock: 'AWS_ACCESS_KEY_ID' // Bedrock uses AWS credentials bedrock: 'AWS_ACCESS_KEY_ID' // Bedrock uses AWS credentials
@@ -726,6 +727,10 @@ function getMcpApiKeyStatus(providerName, projectRoot = null) {
apiKeyToCheck = mcpEnv.XAI_API_KEY; apiKeyToCheck = mcpEnv.XAI_API_KEY;
placeholderValue = 'YOUR_XAI_API_KEY_HERE'; placeholderValue = 'YOUR_XAI_API_KEY_HERE';
break; break;
case 'groq':
apiKeyToCheck = mcpEnv.GROQ_API_KEY;
placeholderValue = 'YOUR_GROQ_API_KEY_HERE';
break;
case 'ollama': case 'ollama':
return true; // No key needed return true; // No key needed
case 'claude-code': case 'claude-code':

View File

@@ -295,6 +295,16 @@
} }
], ],
"groq": [ "groq": [
{
"id": "moonshotai/kimi-k2-instruct",
"swe_score": 0.66,
"cost_per_1m_tokens": {
"input": 1.0,
"output": 3.0
},
"allowed_roles": ["main", "fallback"],
"max_tokens": 16384
},
{ {
"id": "llama-3.3-70b-versatile", "id": "llama-3.3-70b-versatile",
"swe_score": 0.55, "swe_score": 0.55,

View File

@@ -14,6 +14,14 @@ export class GroqProvider extends BaseAIProvider {
this.name = 'Groq'; this.name = 'Groq';
} }
/**
* Returns the environment variable name required for this provider's API key.
* @returns {string} The environment variable name for the Groq API key
*/
getRequiredApiKeyName() {
return 'GROQ_API_KEY';
}
/** /**
* Creates and returns a Groq client instance. * Creates and returns a Groq client instance.
* @param {object} params - Parameters for client initialization * @param {object} params - Parameters for client initialization

View File

@@ -177,6 +177,13 @@ jest.unstable_mockModule('../../src/ai-providers/index.js', () => ({
getRequiredApiKeyName: jest.fn(() => 'XAI_API_KEY'), getRequiredApiKeyName: jest.fn(() => 'XAI_API_KEY'),
isRequiredApiKey: jest.fn(() => true) isRequiredApiKey: jest.fn(() => true)
})), })),
GroqProvider: jest.fn(() => ({
generateText: jest.fn(),
streamText: jest.fn(),
generateObject: jest.fn(),
getRequiredApiKeyName: jest.fn(() => 'GROQ_API_KEY'),
isRequiredApiKey: jest.fn(() => true)
})),
OpenRouterAIProvider: jest.fn(() => ({ OpenRouterAIProvider: jest.fn(() => ({
generateText: jest.fn(), generateText: jest.fn(),
streamText: jest.fn(), streamText: jest.fn(),