From 2769121842b83977e511b14446dd9827ba151cd5 Mon Sep 17 00:00:00 2001 From: GPT8 <57486732+di-sukharev@users.noreply.github.com> Date: Sat, 7 Sep 2024 18:17:17 +0300 Subject: [PATCH] 3.2.2 (#413) * feat(config): add support for groq AI provider, including config validation and engine implementation (#381) * fix migrations (#414) --------- Co-authored-by: Takanori Matsumoto Co-authored-by: BILLY Maxime --- out/cli.cjs | 74 ++++++++++++++++--- out/github-action.cjs | 62 ++++++++++++++-- package-lock.json | 4 +- package.json | 2 +- src/commands/commit.ts | 6 +- src/commands/config.ts | 51 +++++++++++-- src/engine/groq.ts | 10 +++ src/engine/openAi.ts | 9 ++- .../02_set_missing_default_values.ts | 4 +- src/migrations/_run.ts | 1 + src/utils/engine.ts | 4 + 11 files changed, 199 insertions(+), 28 deletions(-) create mode 100644 src/engine/groq.ts diff --git a/out/cli.cjs b/out/cli.cjs index 50fd4e2..a4fe603 100755 --- a/out/cli.cjs +++ b/out/cli.cjs @@ -27331,7 +27331,7 @@ function G3(t2, e3) { // package.json var package_default = { name: "opencommit", - version: "3.2.1", + version: "3.2.2", description: "Auto-generate impressive commits in 1 second. Killing lame commits with AI \u{1F92F}\u{1F52B}", keywords: [ "git", @@ -29918,6 +29918,15 @@ var MODEL_LIST = { "gemini-1.0-pro", "gemini-pro-vision", "text-embedding-004" + ], + groq: [ + "llama3-70b-8192", + "llama3-8b-8192", + "llama-guard-3-8b", + "llama-3.1-8b-instant", + "llama-3.1-70b-versatile", + "gemma-7b-it", + "gemma2-9b-it" ] }; var getDefaultModel = (provider) => { @@ -29928,6 +29937,8 @@ var getDefaultModel = (provider) => { return MODEL_LIST.anthropic[0]; case "gemini": return MODEL_LIST.gemini[0]; + case "groq": + return MODEL_LIST.groq[0]; default: return MODEL_LIST.openai[0]; } @@ -30051,9 +30062,15 @@ var configValidators = { value = "openai"; validateConfig( "OCO_AI_PROVIDER" /* OCO_AI_PROVIDER */, - ["openai", "anthropic", "gemini", "azure", "test", "flowise"].includes( - value - ) || value.startsWith("ollama"), + [ + "openai", + "anthropic", + "gemini", + "azure", + "test", + "flowise", + "groq" + ].includes(value) || value.startsWith("ollama"), `${value} is not supported yet, use 'ollama', 'anthropic', 'azure', 'gemini', 'flowise' or 'openai' (default)` ); return value; @@ -30093,6 +30110,7 @@ var OCO_AI_PROVIDER_ENUM = /* @__PURE__ */ ((OCO_AI_PROVIDER_ENUM2) => { OCO_AI_PROVIDER_ENUM2["AZURE"] = "azure"; OCO_AI_PROVIDER_ENUM2["TEST"] = "test"; OCO_AI_PROVIDER_ENUM2["FLOWISE"] = "flowise"; + OCO_AI_PROVIDER_ENUM2["GROQ"] = "groq"; return OCO_AI_PROVIDER_ENUM2; })(OCO_AI_PROVIDER_ENUM || {}); var defaultConfigPath = (0, import_path.join)((0, import_os.homedir)(), ".opencommit"); @@ -30109,7 +30127,6 @@ var DEFAULT_CONFIG = { OCO_AI_PROVIDER: "openai" /* OPENAI */, OCO_ONE_LINE_COMMIT: false, OCO_TEST_MOCK_TYPE: "commit-message", - OCO_FLOWISE_ENDPOINT: ":", OCO_WHY: false, OCO_GITPUSH: true }; @@ -30169,6 +30186,25 @@ var mergeConfigs = (main, fallback) => { return acc; }, {}); }; +var cleanUndefinedValues = (config7) => { + return Object.fromEntries( + Object.entries(config7).map(([_7, v5]) => { + try { + if (typeof v5 === "string") { + if (v5 === "undefined") + return [_7, void 0]; + if (v5 === "null") + return [_7, null]; + const parsedValue = JSON.parse(v5); + return [_7, parsedValue]; + } + return [_7, v5]; + } catch (error) { + return [_7, v5]; + } + }) + ); +}; var getConfig = ({ envPath = defaultEnvPath, globalPath = defaultConfigPath @@ -30176,7 +30212,8 @@ var getConfig = ({ const envConfig = getEnvConfig(envPath); const globalConfig = getGlobalConfig(globalPath); const config7 = mergeConfigs(envConfig, globalConfig); - return config7; + const cleanConfig = cleanUndefinedValues(config7); + return cleanConfig; }; var setConfig = (keyValues, globalConfigPath = defaultConfigPath) => { const config7 = getConfig({ @@ -44471,7 +44508,19 @@ var OpenAiEngine = class { } }; this.config = config7; - this.client = new OpenAI({ apiKey: config7.apiKey }); + if (!config7.baseURL) { + this.client = new OpenAI({ apiKey: config7.apiKey }); + } else { + this.client = new OpenAI({ apiKey: config7.apiKey, baseURL: config7.baseURL }); + } + } +}; + +// src/engine/groq.ts +var GroqEngine = class extends OpenAiEngine { + constructor(config7) { + config7.baseURL = "https://api.groq.com/openai/v1"; + super(config7); } }; @@ -44499,6 +44548,8 @@ function getEngine() { return new AzureEngine(DEFAULT_CONFIG2); case "flowise" /* FLOWISE */: return new FlowiseEngine(DEFAULT_CONFIG2); + case "groq" /* GROQ */: + return new GroqEngine(DEFAULT_CONFIG2); default: return new OpenAiEngine(DEFAULT_CONFIG2); } @@ -45342,7 +45393,10 @@ ${source_default.grey("\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2 } } } catch (error) { - commitGenerationSpinner.stop("\u{1F4DD} Commit message generated"); + commitGenerationSpinner.stop( + `${source_default.red("\u2716")} Failed to generate the commit message` + ); + console.log(error); const err = error; ce(`${source_default.red("\u2716")} ${err?.message || err}`); process.exit(1); @@ -45677,11 +45731,12 @@ function set_missing_default_values_default() { const entriesToSet = []; for (const entry of Object.entries(DEFAULT_CONFIG)) { const [key, _value] = entry; - if (config7[key] === "undefined") + if (config7[key] === "undefined" || config7[key] === void 0) entriesToSet.push(entry); } if (entriesToSet.length > 0) setConfig(entriesToSet); + console.log(entriesToSet); }; setDefaultConfigValues(getGlobalConfig()); } @@ -45738,6 +45793,7 @@ var runMigrations = async () => { ce( `${source_default.red("Failed to apply migration")} ${migration.name}: ${error}` ); + process.exit(1); } isMigrated = true; } diff --git a/out/github-action.cjs b/out/github-action.cjs index 68b1421..5acd5e0 100644 --- a/out/github-action.cjs +++ b/out/github-action.cjs @@ -48730,6 +48730,15 @@ var MODEL_LIST = { "gemini-1.0-pro", "gemini-pro-vision", "text-embedding-004" + ], + groq: [ + "llama3-70b-8192", + "llama3-8b-8192", + "llama-guard-3-8b", + "llama-3.1-8b-instant", + "llama-3.1-70b-versatile", + "gemma-7b-it", + "gemma2-9b-it" ] }; var getDefaultModel = (provider) => { @@ -48740,6 +48749,8 @@ var getDefaultModel = (provider) => { return MODEL_LIST.anthropic[0]; case "gemini": return MODEL_LIST.gemini[0]; + case "groq": + return MODEL_LIST.groq[0]; default: return MODEL_LIST.openai[0]; } @@ -48863,9 +48874,15 @@ var configValidators = { value = "openai"; validateConfig( "OCO_AI_PROVIDER" /* OCO_AI_PROVIDER */, - ["openai", "anthropic", "gemini", "azure", "test", "flowise"].includes( - value - ) || value.startsWith("ollama"), + [ + "openai", + "anthropic", + "gemini", + "azure", + "test", + "flowise", + "groq" + ].includes(value) || value.startsWith("ollama"), `${value} is not supported yet, use 'ollama', 'anthropic', 'azure', 'gemini', 'flowise' or 'openai' (default)` ); return value; @@ -48911,7 +48928,6 @@ var DEFAULT_CONFIG = { OCO_AI_PROVIDER: "openai" /* OPENAI */, OCO_ONE_LINE_COMMIT: false, OCO_TEST_MOCK_TYPE: "commit-message", - OCO_FLOWISE_ENDPOINT: ":", OCO_WHY: false, OCO_GITPUSH: true }; @@ -48971,6 +48987,25 @@ var mergeConfigs = (main, fallback) => { return acc; }, {}); }; +var cleanUndefinedValues = (config6) => { + return Object.fromEntries( + Object.entries(config6).map(([_3, v2]) => { + try { + if (typeof v2 === "string") { + if (v2 === "undefined") + return [_3, void 0]; + if (v2 === "null") + return [_3, null]; + const parsedValue = JSON.parse(v2); + return [_3, parsedValue]; + } + return [_3, v2]; + } catch (error) { + return [_3, v2]; + } + }) + ); +}; var getConfig = ({ envPath = defaultEnvPath, globalPath = defaultConfigPath @@ -48978,7 +49013,8 @@ var getConfig = ({ const envConfig = getEnvConfig(envPath); const globalConfig = getGlobalConfig(globalPath); const config6 = mergeConfigs(envConfig, globalConfig); - return config6; + const cleanConfig = cleanUndefinedValues(config6); + return cleanConfig; }; var setConfig = (keyValues, globalConfigPath = defaultConfigPath) => { const config6 = getConfig({ @@ -63273,7 +63309,19 @@ var OpenAiEngine = class { } }; this.config = config6; - this.client = new OpenAI({ apiKey: config6.apiKey }); + if (!config6.baseURL) { + this.client = new OpenAI({ apiKey: config6.apiKey }); + } else { + this.client = new OpenAI({ apiKey: config6.apiKey, baseURL: config6.baseURL }); + } + } +}; + +// src/engine/groq.ts +var GroqEngine = class extends OpenAiEngine { + constructor(config6) { + config6.baseURL = "https://api.groq.com/openai/v1"; + super(config6); } }; @@ -63301,6 +63349,8 @@ function getEngine() { return new AzureEngine(DEFAULT_CONFIG2); case "flowise" /* FLOWISE */: return new FlowiseEngine(DEFAULT_CONFIG2); + case "groq" /* GROQ */: + return new GroqEngine(DEFAULT_CONFIG2); default: return new OpenAiEngine(DEFAULT_CONFIG2); } diff --git a/package-lock.json b/package-lock.json index 5d34e5e..aede6fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "opencommit", - "version": "3.2.1", + "version": "3.2.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "opencommit", - "version": "3.2.1", + "version": "3.2.2", "license": "MIT", "dependencies": { "@actions/core": "^1.10.0", diff --git a/package.json b/package.json index 777867b..24d37d5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opencommit", - "version": "3.2.1", + "version": "3.2.2", "description": "Auto-generate impressive commits in 1 second. Killing lame commits with AI 🤯🔫", "keywords": [ "git", diff --git a/src/commands/commit.ts b/src/commands/commit.ts index 8d61df0..a26df26 100644 --- a/src/commands/commit.ts +++ b/src/commands/commit.ts @@ -183,7 +183,11 @@ ${chalk.grey('——————————————————')}` } } } catch (error) { - commitGenerationSpinner.stop('📝 Commit message generated'); + commitGenerationSpinner.stop( + `${chalk.red('✖')} Failed to generate the commit message` + ); + + console.log(error); const err = error as Error; outro(`${chalk.red('✖')} ${err?.message || err}`); diff --git a/src/commands/config.ts b/src/commands/config.ts index c45e2f2..e673633 100644 --- a/src/commands/config.ts +++ b/src/commands/config.ts @@ -76,6 +76,16 @@ export const MODEL_LIST = { 'gemini-1.0-pro', 'gemini-pro-vision', 'text-embedding-004' + ], + + groq: [ + 'llama3-70b-8192', // Meta Llama 3 70B (default one, no daily token limit and 14 400 reqs/day) + 'llama3-8b-8192', // Meta Llama 3 8B + 'llama-guard-3-8b', // Llama Guard 3 8B + 'llama-3.1-8b-instant', // Llama 3.1 8B (Preview) + 'llama-3.1-70b-versatile', // Llama 3.1 70B (Preview) + 'gemma-7b-it', // Gemma 7B + 'gemma2-9b-it' // Gemma 2 9B ] }; @@ -87,6 +97,8 @@ const getDefaultModel = (provider: string | undefined): string => { return MODEL_LIST.anthropic[0]; case 'gemini': return MODEL_LIST.gemini[0]; + case 'groq': + return MODEL_LIST.groq[0]; default: return MODEL_LIST.openai[0]; } @@ -241,9 +253,15 @@ export const configValidators = { validateConfig( CONFIG_KEYS.OCO_AI_PROVIDER, - ['openai', 'anthropic', 'gemini', 'azure', 'test', 'flowise'].includes( - value - ) || value.startsWith('ollama'), + [ + 'openai', + 'anthropic', + 'gemini', + 'azure', + 'test', + 'flowise', + 'groq' + ].includes(value) || value.startsWith('ollama'), `${value} is not supported yet, use 'ollama', 'anthropic', 'azure', 'gemini', 'flowise' or 'openai' (default)` ); @@ -288,7 +306,8 @@ export enum OCO_AI_PROVIDER_ENUM { GEMINI = 'gemini', AZURE = 'azure', TEST = 'test', - FLOWISE = 'flowise' + FLOWISE = 'flowise', + GROQ = 'groq' } export type ConfigType = { @@ -352,7 +371,6 @@ export const DEFAULT_CONFIG = { OCO_AI_PROVIDER: OCO_AI_PROVIDER_ENUM.OPENAI, OCO_ONE_LINE_COMMIT: false, OCO_TEST_MOCK_TYPE: 'commit-message', - OCO_FLOWISE_ENDPOINT: ':', OCO_WHY: false, OCO_GITPUSH: true // todo: deprecate }; @@ -444,6 +462,25 @@ interface GetConfigOptions { setDefaultValues?: boolean; } +const cleanUndefinedValues = (config: ConfigType) => { + return Object.fromEntries( + Object.entries(config).map(([_, v]) => { + try { + if (typeof v === 'string') { + if (v === 'undefined') return [_, undefined]; + if (v === 'null') return [_, null]; + + const parsedValue = JSON.parse(v); + return [_, parsedValue]; + } + return [_, v]; + } catch (error) { + return [_, v]; + } + }) + ); +}; + export const getConfig = ({ envPath = defaultEnvPath, globalPath = defaultConfigPath @@ -453,7 +490,9 @@ export const getConfig = ({ const config = mergeConfigs(envConfig, globalConfig); - return config; + const cleanConfig = cleanUndefinedValues(config); + + return cleanConfig as ConfigType; }; export const setConfig = ( diff --git a/src/engine/groq.ts b/src/engine/groq.ts new file mode 100644 index 0000000..baa6410 --- /dev/null +++ b/src/engine/groq.ts @@ -0,0 +1,10 @@ +import { OpenAiConfig, OpenAiEngine } from './openAi'; + +interface GroqConfig extends OpenAiConfig {} + +export class GroqEngine extends OpenAiEngine { + constructor(config: GroqConfig) { + config.baseURL = 'https://api.groq.com/openai/v1'; + super(config); + } +} \ No newline at end of file diff --git a/src/engine/openAi.ts b/src/engine/openAi.ts index 2f231ee..ea5d9e9 100644 --- a/src/engine/openAi.ts +++ b/src/engine/openAi.ts @@ -4,7 +4,7 @@ import { GenerateCommitMessageErrorEnum } from '../generateCommitMessageFromGitD import { tokenCount } from '../utils/tokenCount'; import { AiEngine, AiEngineConfig } from './Engine'; -interface OpenAiConfig extends AiEngineConfig {} +export interface OpenAiConfig extends AiEngineConfig {} export class OpenAiEngine implements AiEngine { config: OpenAiConfig; @@ -12,7 +12,12 @@ export class OpenAiEngine implements AiEngine { constructor(config: OpenAiConfig) { this.config = config; - this.client = new OpenAI({ apiKey: config.apiKey }); + + if (!config.baseURL) { + this.client = new OpenAI({ apiKey: config.apiKey }); + } else { + this.client = new OpenAI({ apiKey: config.apiKey, baseURL: config.baseURL }); + } } public generateCommitMessage = async ( diff --git a/src/migrations/02_set_missing_default_values.ts b/src/migrations/02_set_missing_default_values.ts index 107fc06..c93779a 100644 --- a/src/migrations/02_set_missing_default_values.ts +++ b/src/migrations/02_set_missing_default_values.ts @@ -10,10 +10,12 @@ export default function () { const entriesToSet: [key: string, value: string | boolean | number][] = []; for (const entry of Object.entries(DEFAULT_CONFIG)) { const [key, _value] = entry; - if (config[key] === 'undefined') entriesToSet.push(entry); + if (config[key] === 'undefined' || config[key] === undefined) + entriesToSet.push(entry); } if (entriesToSet.length > 0) setConfig(entriesToSet); + console.log(entriesToSet); }; setDefaultConfigValues(getGlobalConfig()); diff --git a/src/migrations/_run.ts b/src/migrations/_run.ts index 03a6b1b..bbf3bb8 100644 --- a/src/migrations/_run.ts +++ b/src/migrations/_run.ts @@ -53,6 +53,7 @@ export const runMigrations = async () => { migration.name }: ${error}` ); + process.exit(1); } isMigrated = true; diff --git a/src/utils/engine.ts b/src/utils/engine.ts index f3b3ae0..5930c2f 100644 --- a/src/utils/engine.ts +++ b/src/utils/engine.ts @@ -7,6 +7,7 @@ import { GeminiEngine } from '../engine/gemini'; import { OllamaEngine } from '../engine/ollama'; import { OpenAiEngine } from '../engine/openAi'; import { TestAi, TestMockType } from '../engine/testAi'; +import { GroqEngine } from '../engine/groq'; export function getEngine(): AiEngine { const config = getConfig(); @@ -39,6 +40,9 @@ export function getEngine(): AiEngine { case OCO_AI_PROVIDER_ENUM.FLOWISE: return new FlowiseEngine(DEFAULT_CONFIG); + case OCO_AI_PROVIDER_ENUM.GROQ: + return new GroqEngine(DEFAULT_CONFIG); + default: return new OpenAiEngine(DEFAULT_CONFIG); }