diff --git a/cli/commands/config.command.ts b/cli/commands/config.command.ts index e294bfc..da643f7 100644 --- a/cli/commands/config.command.ts +++ b/cli/commands/config.command.ts @@ -2,6 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import inquirer from 'inquirer'; import chalk from 'chalk'; +import { getModels } from '../../src/utils/get-models'; const CONFIG_FILE = '.codewave.config.json'; @@ -161,176 +162,20 @@ async function initializeConfig(): Promise { value: 'lm-studio', short: 'LM Studio', }, + { name: 'Groq', value: 'groq', short: 'Groq' }, ], default: defaultProvider, }, ]); - // Provider-specific configuration with available models - const providerInfo = { - anthropic: { - defaultModel: 'claude-haiku-4-5-20251001', - models: [ - { - name: 'claude-haiku-4-5-20251001 (recommended) - Cost-optimized for multi-agent discussion (ultra-fast)', - value: 'claude-haiku-4-5-20251001', - }, - { - name: 'claude-sonnet-4-5-20250929 - Latest generation (best quality)', - value: 'claude-sonnet-4-5-20250929', - }, - { - name: 'claude-opus-4-1-20250805 - Most powerful (maximum accuracy)', - value: 'claude-opus-4-1-20250805', - }, - ], - keyFormat: 'sk-ant-...', - url: 'https://console.anthropic.com/', - }, - openai: { - defaultModel: 'gpt-4o-mini', - models: [ - { name: 'gpt-4o-mini (recommended) - Fast and cost-effective', value: 'gpt-4o-mini' }, - { name: 'gpt-4o - Latest multimodal model', value: 'gpt-4o' }, - { name: 'o3-mini - Advanced reasoning (cost-efficient)', value: 'o3-mini-2025-01-31' }, - { name: 'o3 - Most powerful reasoning model', value: 'o3' }, - ], - keyFormat: 'sk-...', - url: 'https://platform.openai.com/', - }, - google: { - defaultModel: 'gemini-2.5-flash', - models: [ - { - name: 'gemini-2.5-flash (recommended) - Best cost-performance ratio', - value: 'gemini-2.5-flash', - }, - { - name: 'gemini-2.5-flash-lite - Fastest and most efficient', - value: 'gemini-2.5-flash-lite', - }, - { name: 'gemini-2.5-pro - Best reasoning capabilities', value: 'gemini-2.5-pro' }, - ], - keyFormat: 'AIza...', - url: 'https://ai.google.dev/', - }, - xai: { - defaultModel: 'grok-4-fast-non-reasoning', - models: [ - { - name: 'grok-4-fast-non-reasoning (recommended) - Latest with 40% fewer tokens', - value: 'grok-4-fast-non-reasoning', - }, - { name: 'grok-4.2 - Polished and refined', value: 'grok-4.2' }, - { name: 'grok-4 - Advanced reasoning model', value: 'grok-4-0709' }, - ], - keyFormat: 'xai-...', - url: 'https://console.x.ai/', - }, - ollama: { - defaultModel: 'gpt-oss-20b', - models: [ - { - name: 'gpt-oss-20b (recommended) - Balanced reasoning and performance', - value: 'gpt-oss-20b', - }, - ], - keyFormat: '(no API key required)', - url: 'https://ollama.com/library', - }, - 'lm-studio': { - defaultModel: 'local-model', // LM Studio often ignores the model name if only one is loaded - models: [ - { - name: 'Load from LM Studio (uses currently loaded model)', - value: 'local-model', - }, - ], - keyFormat: '(no API key required)', - url: 'http://localhost:1234', - }, - groq: { - defaultModel: 'openai/gpt-oss-120b', - models: [ - { - name: 'openai/gpt-oss-120b (recommended) - Balanced reasoning and performance', - value: 'openai/gpt-oss-120b', - }, - ], - keyFormat: 'gsk_...', - url: 'https://console.groq.com/', - }, - }; - - const info = providerInfo[provider as keyof typeof providerInfo]; - - // Select model for the chosen provider - console.log(chalk.cyan(`\n🎯 Available ${provider} models:\n`)); - console.log( - chalk.gray('💡 CodeWave uses multi-agent discussion (3 rounds) to refine evaluations.') - ); - console.log( - chalk.gray(' Cheaper models like Haiku achieve 95%+ quality through discussion refinement.\n') - ); - - // Use existing model as default if it's valid for this provider, otherwise use provider default - let defaultModel = info.defaultModel; - if (config.llm.model && info.models.some((m) => m.value === config.llm.model)) { - defaultModel = config.llm.model; - } - - const { selectedModel } = await inquirer.prompt([ - { - type: 'list', - name: 'selectedModel', - message: `Choose ${provider} model:`, - choices: info.models, - default: defaultModel, - }, - ]); - - // Show cost comparison for selected provider - const costByProvider = { - anthropic: { - 'claude-haiku-4-5-20251001': '$0.025/commit', - 'claude-sonnet-4-5-20250929': '$0.15/commit', - 'claude-opus-4-1-20250805': '$0.40/commit', - }, - openai: { - 'gpt-4o-mini': '$0.008/commit', - 'gpt-4o': '$0.10/commit', - 'o3-mini-2025-01-31': '$0.20/commit', - o3: '$0.40/commit', - }, - google: { - 'gemini-2.5-flash': '$0.010/commit', - 'gemini-2.5-flash-lite': '$0.006/commit', - 'gemini-2.5-pro': '$0.06/commit', - }, - xai: { - 'grok-4-fast-non-reasoning': '$0.08/commit', - 'grok-4.2': '$0.08/commit', - 'grok-4-0709': '$0.08/commit', - }, - }; - - const providerCosts = costByProvider[provider as keyof typeof costByProvider]; - if (providerCosts) { - const cost = providerCosts[selectedModel as keyof typeof providerCosts]; - if (cost) { - console.log(chalk.gray(`\n✓ Selected: ${selectedModel}`)); - console.log(chalk.gray(` Cost: ${cost} (estimated for 3-round multi-agent discussion)`)); - } - } + config.llm.provider = provider; - let apiKey = ''; + let apiKey = null; if (provider !== 'ollama' && provider !== 'lm-studio') { - console.log(chalk.gray(`\nGet your API key at: ${info.url}\n`)); - const existingApiKey = config.apiKeys[provider]; const apiKeyPromptMessage = existingApiKey - ? `Enter ${provider} API key (${info.keyFormat}) [press Enter to keep existing]:` - : `Enter ${provider} API key (${info.keyFormat}):`; + ? `Enter ${provider} API key [press Enter to keep existing]:` + : `Enter ${provider} API key:`; const response = await inquirer.prompt([ { @@ -355,8 +200,65 @@ async function initializeConfig(): Promise { if (apiKey && apiKey.trim().length > 0) { config.apiKeys[provider] = apiKey.trim(); } - config.llm.provider = provider; + + if (provider === 'ollama' || provider === 'lm-studio') { + let existingBaseUrl = config.llm.baseUrl; + const baseUrlPromptMessage = existingBaseUrl + ? `Enter ${provider} base URL [press Enter to keep existing] (${existingBaseUrl}):` + : `Enter ${provider} base URL:`; + + if (!existingBaseUrl) { + existingBaseUrl = + provider === 'ollama' ? 'http://localhost:11434' : 'http://localhost:1234/v1'; + } + const { baseUrl } = await inquirer.prompt([ + { + type: 'input', + name: 'baseUrl', + message: baseUrlPromptMessage, + default: existingBaseUrl, + }, + ]); + config.llm.baseUrl = baseUrl; + } + + const models = await getModels(config); + + // Select model for the chosen provider + console.log(chalk.cyan(`\n🎯 Available ${provider} models:\n`)); + console.log( + chalk.gray('💡 CodeWave uses multi-agent discussion (3 rounds) to refine evaluations.') + ); + console.log( + chalk.gray(' Cheaper models like Haiku achieve 95%+ quality through discussion refinement.\n') + ); + + const { selectedModel } = await inquirer.prompt([ + { + type: 'list', + name: 'selectedModel', + message: `Choose ${provider} model:`, + choices: models, + default: models[0].value, + loop: false, + }, + ]); config.llm.model = selectedModel; + const metadata = models.find((model) => model.value === selectedModel); + + if (metadata) { + const inputPricePerToken = parseFloat(metadata.pricing.input); + const outputPricePerToken = parseFloat(metadata.pricing.output); + const cost = (inputPricePerToken + outputPricePerToken) * DEFAULT_CONFIG.llm.maxTokens * 3; + if (cost) { + console.log(chalk.gray(`\n✓ Selected: ${chalk.cyanBright(selectedModel)}`)); + console.log( + chalk.gray( + ` Cost: ${chalk.green(`$${cost.toFixed(2)} USD`)} per 3-round multi-agent discussion (estimated)` + ) + ); + } + } console.log(chalk.green(`\n✅ Configured to use: ${provider} (${selectedModel})`)); diff --git a/cli/commands/evaluate-command.ts b/cli/commands/evaluate-command.ts index 21d2223..b0023d0 100644 --- a/cli/commands/evaluate-command.ts +++ b/cli/commands/evaluate-command.ts @@ -150,7 +150,7 @@ export async function runEvaluateCommand(args: string[]) { // Get API key for selected provider const provider = config.llm.provider; - const apiKey = config.apiKeys[provider]; + const apiKey = config.apiKeys?.[provider as keyof typeof config.apiKeys]; if (!apiKey) { console.log(chalk.red(`\n❌ No API key configured for provider: ${provider}\n`)); diff --git a/package-lock.json b/package-lock.json index eb5ffe8..22d60a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@langchain/langgraph": "^1.0.2", "@langchain/ollama": "^1.0.3", "@langchain/openai": "^1.1.3", + "@langchain/xai": "^1.0.2", "@types/cli-progress": "^3.11.6", "@types/inquirer": "^9.0.9", "chalk": "^4.1.2", @@ -325,7 +326,6 @@ "resolved": "https://registry.npmjs.org/@langchain/core/-/core-1.1.1.tgz", "integrity": "sha512-vdUoj2CVbb+0Qszi8llP34vdUCfP7bfA9VoFr4Se1pFGu7VAPnk8lBnRat9IvqSxMfTvOHJSd7Rn6TUPjzKsnA==", "license": "MIT", - "peer": true, "dependencies": { "@cfworker/json-schema": "^4.0.2", "ansi-styles": "^5.0.0", @@ -527,6 +527,21 @@ "@langchain/core": "^1.0.0" } }, + "node_modules/@langchain/xai": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@langchain/xai/-/xai-1.0.2.tgz", + "integrity": "sha512-ImwVq5wWzBZXvkUNFE02qw11rMK7a+1f537xVisgoaRODng5oQv4AfPlNEBMT2MKLv4C6POSY1rhC7f/YKriGQ==", + "license": "MIT", + "dependencies": { + "@langchain/openai": "1.1.3" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@langchain/core": "^1.0.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -702,7 +717,6 @@ "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", @@ -881,7 +895,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1466,7 +1479,6 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -1523,7 +1535,6 @@ "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -3037,7 +3048,6 @@ "integrity": "sha512-QgODejq9K3OzoBbuyobZlUhznP5SKwPqp+6Q6xw6o8gnhr4O85L2U915iM2IDcfF2NPXVaM9zlo9tdwipnYwzg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -3544,7 +3554,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3741,7 +3750,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index c0f4193..717d040 100644 --- a/package.json +++ b/package.json @@ -97,6 +97,7 @@ "@langchain/langgraph": "^1.0.2", "@langchain/ollama": "^1.0.3", "@langchain/openai": "^1.1.3", + "@langchain/xai": "^1.0.2", "@types/cli-progress": "^3.11.6", "@types/inquirer": "^9.0.9", "chalk": "^4.1.2", diff --git a/src/config/config.interface.ts b/src/config/config.interface.ts index 23ce8b6..bc8f18c 100644 --- a/src/config/config.interface.ts +++ b/src/config/config.interface.ts @@ -9,8 +9,6 @@ export interface AppConfig { openai: string; google: string; xai: string; - ollama: string; - 'lm-studio': string; groq: string; }; llm: { @@ -18,7 +16,7 @@ export interface AppConfig { model: string; temperature: number; maxTokens: number; - baseUrl?: string; + baseUrl?: string | undefined; }; agents: { enabled: string[]; diff --git a/src/config/default-config.ts b/src/config/default-config.ts index f6398e1..a6c41e2 100644 --- a/src/config/default-config.ts +++ b/src/config/default-config.ts @@ -9,8 +9,6 @@ export const DEFAULT_CONFIG: AppConfig = { openai: '', google: '', xai: '', - ollama: '', - 'lm-studio': '', groq: '', }, llm: { diff --git a/src/constants/provider-models.ts b/src/constants/provider-models.ts new file mode 100644 index 0000000..2831939 --- /dev/null +++ b/src/constants/provider-models.ts @@ -0,0 +1,500 @@ +export const PROVIDER_MODELS = { + groq: [ + { + name: 'Qwen 3 32B - [High Intelligence, Low Cost, Super Fast Speed]', + value: 'qwen/qwen3-32b', + pricing: { + input: '0.00000029', + output: '0.00000059', + }, + }, + { + name: 'meta-llama/llama-4-scout-17b-16e-instruct - [Medium Intelligence, Low Cost, Super Fast Speed]', + value: 'meta-llama/llama-4-scout-17b-16e-instruct', + pricing: { + input: '0.00000011', + output: '0.00000034', + }, + }, + { + name: 'llama-3.3-70b-versatile - [High Intelligence, Low Cost, Super Fast Speed]', + value: 'llama-3.3-70b-versatile', + pricing: { + input: '0.00000059', + output: '0.00000079', + }, + }, + { + name: 'moonshotai/kimi-k2-instruct - [Medium Intelligence, Low Cost, Super Fast Speed]', + value: 'moonshotai/kimi-k2-instruct', + pricing: { + input: '0.000001', + output: '0.000003', + }, + }, + { + name: 'moonshotai/kimi-k2-instruct-0905 - [Medium Intelligence, Low Cost, Super Fast Speed]', + value: 'moonshotai/kimi-k2-instruct-0905', + pricing: { + input: '0.000001', + output: '0.000003', + }, + }, + { + name: 'meta-llama/llama-4-maverick-17b-128e-instruct - [Medium Intelligence, Low Cost, Super Fast Speed]', + value: 'meta-llama/llama-4-maverick-17b-128e-instruct', + pricing: { + input: '0.0000002', + output: '0.0000006', + }, + }, + { + name: 'GPT-OSS 120B - [Medium-High Intelligence, Low Cost, Super Fast Speed]', + value: 'openai/gpt-oss-120b', + pricing: { + input: '0.00000015', + output: '0.0000006', + }, + }, + { + name: 'GPT-OSS 20B - [Medium Intelligence, Low Cost, Super Fast Speed]', + value: 'openai/gpt-oss-20b', + pricing: { + input: '0.000000075', + output: '0.0000003', + }, + }, + { + name: 'llama-3.1-8b-instant - [Medium Intelligence, Low Cost, Super Fast Speed]', + value: 'llama-3.1-8b-instant', + pricing: { + input: '0.00000005', + output: '0.00000008', + }, + }, + ], + anthropic: [ + { + name: 'Claude Opus 4.5 - [High Intelligence, High Cost, Slow Speed]', + value: 'claude-opus-4-5-20251101', + pricing: { + input: '0.000005', + output: '0.000025', + }, + }, + { + name: 'Claude Haiku 4.5 - [Medium Intelligence, Low Cost, Fast Speed]', + value: 'claude-haiku-4-5-20251001', + pricing: { + input: '0.000001', + output: '0.000005', + }, + }, + { + name: 'Claude Sonnet 4.5 - [High Intelligence, Medium Cost, Standard Speed]', + value: 'claude-sonnet-4-5-20250929', + pricing: { + input: '0.000003', + output: '0.000015', + }, + }, + { + name: 'Claude Opus 4.1 - [High Intelligence, High Cost, Slow Speed]', + value: 'claude-opus-4-1-20250805', + pricing: { + input: '0.000015', + output: '0.000075', + }, + }, + { + name: 'Claude Opus 4 - [High Intelligence, High Cost, Slow Speed]', + value: 'claude-opus-4-20250514', + pricing: { + input: '0.000015', + output: '0.000075', + }, + }, + { + name: 'Claude Sonnet 4 - [High Intelligence, Medium Cost, Standard Speed]', + value: 'claude-sonnet-4-20250514', + pricing: { + input: '0.000003', + output: '0.000015', + }, + }, + { + name: 'Claude Sonnet 3.7 - [Medium Intelligence, Medium Cost, Standard Speed]', + value: 'claude-3-7-sonnet-20250219', + pricing: { + input: '0.000003', + output: '0.000015', + }, + }, + { + name: 'Claude Haiku 3.5 - [Medium Intelligence, Low Cost, Fast Speed]', + value: 'claude-3-5-haiku-20241022', + pricing: { + input: '0.0000008', + output: '0.000004', + }, + }, + { + name: 'Claude Haiku 3 - [Medium Intelligence, Low Cost, Fast Speed]', + value: 'claude-3-haiku-20240307', + pricing: { + input: '0.00000025', + output: '0.00000125', + }, + }, + { + name: 'Claude Opus 3 - [Medium Intelligence, High Cost, Slow Speed]', + value: 'claude-3-opus-20240229', + pricing: { + input: '0.000015', + output: '0.000075', + }, + }, + ], + openai: [ + { + name: 'gpt-4 - [Medium Intelligence, High Cost, Standard Speed]', + value: 'gpt-4', + pricing: { + input: '0.00003', + output: '0.00006', + }, + }, + { + name: 'gpt-3.5-turbo - [Medium Intelligence, Low Cost, Fast Speed]', + value: 'gpt-3.5-turbo', + pricing: { + input: '0.0000005', + output: '0.0000015', + }, + }, + { + name: 'gpt-5.1-codex-mini - [Medium-High Intelligence, Medium Cost, Fast Speed]', + value: 'gpt-5.1-codex-mini', + pricing: { + input: '0.00000025', + output: '0.000002', + }, + }, + { + name: 'gpt-5.1 - [High Intelligence, High Cost, Standard Speed]', + value: 'gpt-5.1', + pricing: { + input: '0.00000125', + output: '0.00001', + }, + }, + { + name: 'gpt-5.1-codex - [High Intelligence, High Cost, Standard Speed]', + value: 'gpt-5.1-codex', + pricing: { + input: '0.00000125', + output: '0.00001', + }, + }, + { + name: 'gpt-3.5-turbo-instruct - [Medium Intelligence, Low Cost, Fast Speed]', + value: 'gpt-3.5-turbo-instruct', + pricing: { + input: '0.0000015', + output: '0.000002', + }, + }, + { + name: 'gpt-4-1106-preview - [Medium-High Intelligence, Medium Cost, Standard Speed]', + value: 'gpt-4-1106-preview', + pricing: { + input: '0.00001', + output: '0.00003', + }, + }, + { + name: 'gpt-3.5-turbo-1106 - [Medium Intelligence, Low Cost, Fast Speed]', + value: 'gpt-3.5-turbo-1106', + pricing: { + input: '0.000003', + output: '0.000004', + }, + }, + { + name: 'gpt-4-0125-preview - [Medium-High Intelligence, Medium Cost, Standard Speed]', + value: 'gpt-4-0125-preview', + pricing: { + input: '0.00001', + output: '0.00003', + }, + }, + { + name: 'gpt-4-turbo-preview - [Medium-High Intelligence, Medium Cost, Fast Speed]', + value: 'gpt-4-turbo-preview', + pricing: { + input: '0.00001', + output: '0.00003', + }, + }, + { + name: 'gpt-3.5-turbo-0125 - [Medium Intelligence, Low Cost, Fast Speed]', + value: 'gpt-3.5-turbo-0125', + pricing: { + input: '0.000003', + output: '0.000004', + }, + }, + { + name: 'gpt-4-turbo - [Medium-High Intelligence, Medium Cost, Fast Speed]', + value: 'gpt-4-turbo', + pricing: { + input: '0.00001', + output: '0.00003', + }, + }, + { + name: 'gpt-4-turbo-2024-04-09 - [Medium-High Intelligence, Medium Cost, Fast Speed]', + value: 'gpt-4-turbo-2024-04-09', + pricing: { + input: '0.00001', + output: '0.00003', + }, + }, + { + name: 'gpt-4o - [High Intelligence, Medium Cost, Standard Speed]', + value: 'gpt-4o', + pricing: { + input: '0.0000025', + output: '0.00001', + }, + }, + { + name: 'gpt-4o-mini - [Medium-High Intelligence, Low Cost, Fast Speed]', + value: 'gpt-4o-mini', + pricing: { + input: '0.00000015', + output: '0.0000006', + }, + }, + { + name: 'o1 - [High Intelligence, High Cost, Standard Speed, Reasoning]', + value: 'o1', + pricing: { + input: '0.00015', + output: '0.0006', + }, + }, + { + name: 'o3-mini - [Medium-High Intelligence, Medium Cost, Fast Speed, Reasoning]', + value: 'o3-mini', + pricing: { + input: '0.0000011', + output: '0.0000044', + }, + }, + { + name: 'o1-pro - [High Intelligence, High Cost, Standard Speed, Reasoning]', + value: 'o1-pro', + pricing: { + input: '0.00015', + output: '0.0006', + }, + }, + { + name: 'o3 - [High Intelligence, High Cost, Standard Speed, Reasoning]', + value: 'o3', + pricing: { + input: '0.00001', + output: '0.00004', + }, + }, + { + name: 'o4-mini - [Medium-High Intelligence, Medium Cost, Fast Speed, Reasoning]', + value: 'o4-mini', + pricing: { + input: '0.000002', + output: '0.000008', + }, + }, + { + name: 'gpt-4.1 - [Medium Intelligence, High Cost, Standard Speed]', + value: 'gpt-4.1', + pricing: { + input: '0.000002', + output: '0.000008', + }, + }, + { + name: 'gpt-4.1-mini - [Medium Intelligence, Low Cost, Fast Speed]', + value: 'gpt-4.1-mini', + pricing: { + input: '0.0000004', + output: '0.0000016', + }, + }, + { + name: 'gpt-4.1-nano - [Low Intelligence, Low Cost, Fast Speed]', + value: 'gpt-4.1-nano', + pricing: { + input: '0.0000001', + output: '0.0000004', + }, + }, + { + name: 'o3-pro - [High Intelligence, High Cost, Standard Speed, Reasoning]', + value: 'o3-pro', + pricing: { + input: '0.00002', + output: '0.00008', + }, + }, + { + name: 'gpt-5 - [High Intelligence, High Cost, Standard Speed]', + value: 'gpt-5', + pricing: { + input: '0.00000025', + output: '0.000002', + }, + }, + { + name: 'gpt-5-mini - [Medium-High Intelligence, Medium Cost, Fast Speed]', + value: 'gpt-5-mini', + pricing: { + input: '0.00000025', + output: '0.000002', + }, + }, + { + name: 'gpt-5-nano - [Medium-High Intelligence, High Cost, Fast Speed]', + value: 'gpt-5-nano', + pricing: { + input: '0.00000005', + output: '0.0000004', + }, + }, + { + name: 'gpt-5-codex - [High Intelligence, High Cost, Standard Speed]', + value: 'gpt-5-codex', + pricing: { + input: '0.00000125', + output: '0.00001', + }, + }, + { + name: 'gpt-5-pro - [High Intelligence, High Cost, Standard Speed]', + value: 'gpt-5-pro', + pricing: { + input: '0.000015', + output: '0.00012', + }, + }, + ], + google: [ + { + name: 'Gemini 2.5 Flash - [Medium Intelligence, Low Cost, Fast Speed]', + value: 'models/gemini-2.5-flash', + pricing: { + input: '0.0000003', + output: '0.0000025', + }, + }, + { + name: 'Gemini 2.5 Pro - [Medium-High Intelligence, Medium Cost, Fast Speed]', + value: 'models/gemini-2.5-pro', + pricing: { + input: '0.00000125', + output: '0.00001', + }, + }, + { + name: 'Gemini 2.5 Flash-Lite - [Medium Intelligence, Low Cost, Fast Speed]', + value: 'models/gemini-2.5-flash-lite', + pricing: { + input: '0.0000001', + output: '0.0000004', + }, + }, + { + name: 'Gemini 3 Pro Preview - [Medium-High Intelligence, Medium Cost, Fast Speed]', + value: 'models/gemini-3-pro-preview', + pricing: { + input: '0.000002', + output: '0.000012', + }, + }, + ], + xai: [ + { + name: 'grok-2-1212 - [Medium Intelligence, Medium Cost, Standard Speed]', + value: 'grok-2-1212', + pricing: { + input: '0', + output: '0', + }, + }, + { + name: 'grok-3 - [High Intelligence, Medium Cost, Standard Speed]', + value: 'grok-3', + pricing: { + input: '0.000003', + output: '0.000015', + }, + }, + { + name: 'grok-3-mini - [Medium-High Intelligence, Low Cost, Fast Speed]', + value: 'grok-3-mini', + pricing: { + input: '0.0000003', + output: '0.0000005', + }, + }, + { + name: 'Grok 4 (July 2025) - [High Intelligence, Medium Cost, Standard Speed]', + value: 'grok-4-0709', + pricing: { + input: '0.000003', + output: '0.000015', + }, + }, + { + name: 'Grok 4.1 Fast - [High Intelligence, Medium Cost, Fast Speed, Reasoning]', + value: 'grok-4-1-fast-non-reasoning', + pricing: { + input: '0.0000002', + output: '0.0000005', + }, + }, + { + name: 'Grok 4.1 Fast Reasoning - [High Intelligence, Medium Cost, Fast Speed, Reasoning]', + value: 'grok-4-1-fast-reasoning', + pricing: { + input: '0.0000002', + output: '0.0000005', + }, + }, + { + name: 'Grok 4 Fast - [High Intelligence, Medium Cost, Fast Speed, Reasoning]', + value: 'grok-4-fast-non-reasoning', + pricing: { + input: '0.0000002', + output: '0.0000005', + }, + }, + { + name: 'Grok 4 Fast Reasoning - [High Intelligence, Medium Cost, Fast Speed, Reasoning]', + value: 'grok-4-fast-reasoning', + pricing: { + input: '0.0000002', + output: '0.0000005', + }, + }, + { + name: 'Grok Code Fast 1 - [Medium Intelligence, Medium Cost, Fast Speed]', + value: 'grok-code-fast-1', + pricing: { + input: '0.0000002', + output: '0.0000015', + }, + }, + ], +} as const; diff --git a/src/llm/llm-service.ts b/src/llm/llm-service.ts index a702f1a..f75d429 100644 --- a/src/llm/llm-service.ts +++ b/src/llm/llm-service.ts @@ -3,6 +3,7 @@ import { ChatAnthropic } from '@langchain/anthropic'; import { ChatGoogleGenerativeAI } from '@langchain/google-genai'; import { ChatOllama } from '@langchain/ollama'; import { ChatGroq } from '@langchain/groq'; +import { ChatXAI } from '@langchain/xai'; import { AppConfig } from '../config/config.interface'; export class LLMService { @@ -76,14 +77,11 @@ export class LLMService { }); case 'xai': - return new ChatOpenAI({ - openAIApiKey: apiKey, + return new ChatXAI({ + apiKey, temperature, maxTokens, - modelName: model, - configuration: { - baseURL: 'https://api.x.ai/v1', - }, + model, }); case 'groq': { return new ChatGroq({ diff --git a/src/types/model.types.ts b/src/types/model.types.ts new file mode 100644 index 0000000..0e3b9df --- /dev/null +++ b/src/types/model.types.ts @@ -0,0 +1,48 @@ +import { PROVIDER_MODELS } from '../constants/provider-models'; + +export interface GenericModel { + name: string; + value: string; + pricing: { + input: string; + output: string; + }; +} + +export type LLMProvider = keyof typeof PROVIDER_MODELS; +export type LLMProviderModels = (typeof PROVIDER_MODELS)[LLMProvider][number]['value']; +export type Models = { [key in LLMProvider]: GenericModel[] }; + +export interface OllamaModel { + name: string; + model: string; +} + +export interface LMStudioModel { + id: string; +} + +export interface GroqModel { + id: string; +} + +export interface AnthropicModel { + id: string; + display_name: string; +} + +export interface OpenAIModel { + id: string; +} + +export interface GoogleModel { + name: string; + displayName: string; + baseModelId: string; + inputTokenLimit: number; + outputTokenLimit: number; +} + +export interface XAIModel { + id: string; +} diff --git a/src/utils/get-models.ts b/src/utils/get-models.ts new file mode 100644 index 0000000..42840bf --- /dev/null +++ b/src/utils/get-models.ts @@ -0,0 +1,67 @@ +import { AppConfig } from 'config/config.interface'; +import { GenericModel, LLMProvider, LMStudioModel, OllamaModel } from 'types/model.types'; +import { PROVIDER_MODELS } from '../constants/provider-models'; + +export async function getModels(config: AppConfig): Promise { + const provider = config.llm.provider; + const baseUrl = config.llm.baseUrl; + + if (!provider) { + throw new Error('Provider is required'); + } + + let models: GenericModel[] = []; + + switch (provider) { + case 'ollama': + models = await getOllamaModels(baseUrl); + break; + case 'lm-studio': + models = await getLMStudioModels(baseUrl); + break; + default: { + models = (await getProviderModels(provider)) as GenericModel[]; + break; + } + } + return models; +} + +async function getOllamaModels(baseUrl: string | undefined): Promise { + const response = await fetch(`${baseUrl}/api/tags`); + + if (!response.ok) { + throw new Error(`Failed to fetch models from ${baseUrl}`); + } + + const data = (await response.json()) as { models: OllamaModel[] }; + return data.models.map((model) => ({ + name: model.name, + value: model.model, + pricing: { + input: '0', + output: '0', + }, + })); +} + +async function getLMStudioModels(baseUrl: string | undefined): Promise { + const response = await fetch(`${baseUrl}/models`); + + if (!response.ok) { + throw new Error(`Failed to fetch models from ${baseUrl}`); + } + const data = (await response.json()) as { data: LMStudioModel[] }; + return data.data.map((model) => ({ + name: model.id, + value: model.id, + pricing: { + input: '0', + output: '0', + }, + })); +} + +async function getProviderModels(provider: LLMProvider): Promise { + return PROVIDER_MODELS[provider]; +}