3.2.3 (#431)
* 378: fix hook env (#402) * fix(prepare-commit-msg-hook): update error handling to provide clearer instructions for setting API keys and improve user guidance * Fix: a bug that causes an error when pushing without setting git remote (#396) * update deploy commands * feat(cli): add context flag for providing additional commit message input * Fix [Bug]: punycode` module is deprecated #426 (#433) Signed-off-by: Tiger Kaovilai <passawit.kaovilai@gmail.com> * npm audit fix (#432) Signed-off-by: Tiger Kaovilai <passawit.kaovilai@gmail.com> * Feat: Add an option to `Don't push` when there are multiple git remotes (#434) --------- Co-authored-by: GPT8 <57486732+di-sukharev@users.noreply.github.com> * feat(engine): add support for MLX AI provider (#437) --------- Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com> Co-authored-by: Emmanuel Ferdman <emmanuelferdman@gmail.com> * feat(config, engine): add support for Mistral AI provider and engine (#436) * docs(CONTRIBUTING.md): update `TODO.md` reference (#435) Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com> * feat(config, engine): add support for Mistral AI provider and engine * ``` feat(package): add mistralai and zod dependencies ``` * fix: recreate package-lock.json with node20 * fix: recreate package-lock.json with node v20.18.1 based on branch dev --------- Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com> Co-authored-by: Emmanuel Ferdman <emmanuelferdman@gmail.com> Co-authored-by: pedro-valentim <> --------- Signed-off-by: Tiger Kaovilai <passawit.kaovilai@gmail.com> Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com> Co-authored-by: Takanori Matsumoto <matscube@gmail.com> Co-authored-by: BILLY Maxime <ozeliurs@gmail.com> Co-authored-by: Welington Sampaio <welington.sampaio@icloud.com> Co-authored-by: Tiger Kaovilai <passawit.kaovilai@gmail.com> Co-authored-by: albi ⚡️ <sigismondi.alberto@gmail.com> Co-authored-by: Emmanuel Ferdman <emmanuelferdman@gmail.com> Co-authored-by: Pedro Valentim Silva Leite <18179935+pedro-valentim@users.noreply.github.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import { OpenAIClient as AzureOpenAIClient } from '@azure/openai';
|
||||
import { GoogleGenerativeAI as GeminiClient } from '@google/generative-ai';
|
||||
import { AxiosInstance as RawAxiosClient } from 'axios';
|
||||
import { OpenAI as OpenAIClient } from 'openai';
|
||||
import { Mistral as MistralClient } from '@mistralai/mistralai';
|
||||
|
||||
export interface AiEngineConfig {
|
||||
apiKey: string;
|
||||
@@ -17,7 +18,8 @@ type Client =
|
||||
| AzureOpenAIClient
|
||||
| AnthropicClient
|
||||
| RawAxiosClient
|
||||
| GeminiClient;
|
||||
| GeminiClient
|
||||
| MistralClient;
|
||||
|
||||
export interface AiEngine {
|
||||
config: AiEngineConfig;
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import axios from 'axios';
|
||||
import { Mistral } from '@mistralai/mistralai';
|
||||
import { OpenAI } from 'openai';
|
||||
import { GenerateCommitMessageErrorEnum } from '../generateCommitMessageFromGitDiff';
|
||||
import { tokenCount } from '../utils/tokenCount';
|
||||
import { AiEngine, AiEngineConfig } from './Engine';
|
||||
import {
|
||||
AssistantMessage as MistralAssistantMessage,
|
||||
SystemMessage as MistralSystemMessage,
|
||||
ToolMessage as MistralToolMessage,
|
||||
UserMessage as MistralUserMessage
|
||||
} from '@mistralai/mistralai/models/components';
|
||||
|
||||
export interface MistralAiConfig extends AiEngineConfig {}
|
||||
export type MistralCompletionMessageParam = Array<
|
||||
| (MistralSystemMessage & { role: "system" })
|
||||
| (MistralUserMessage & { role: "user" })
|
||||
| (MistralAssistantMessage & { role: "assistant" })
|
||||
| (MistralToolMessage & { role: "tool" })
|
||||
>
|
||||
|
||||
export class MistralAiEngine implements AiEngine {
|
||||
config: MistralAiConfig;
|
||||
client: Mistral;
|
||||
|
||||
constructor(config: MistralAiConfig) {
|
||||
this.config = config;
|
||||
|
||||
if (!config.baseURL) {
|
||||
this.client = new Mistral({ apiKey: config.apiKey });
|
||||
} else {
|
||||
this.client = new Mistral({ apiKey: config.apiKey, serverURL: config.baseURL });
|
||||
}
|
||||
}
|
||||
|
||||
public generateCommitMessage = async (
|
||||
messages: Array<OpenAI.Chat.Completions.ChatCompletionMessageParam>
|
||||
): Promise<string | null> => {
|
||||
const params = {
|
||||
model: this.config.model,
|
||||
messages: messages as MistralCompletionMessageParam,
|
||||
topP: 0.1,
|
||||
maxTokens: this.config.maxTokensOutput
|
||||
};
|
||||
|
||||
try {
|
||||
const REQUEST_TOKENS = messages
|
||||
.map((msg) => tokenCount(msg.content as string) + 4)
|
||||
.reduce((a, b) => a + b, 0);
|
||||
|
||||
if (
|
||||
REQUEST_TOKENS >
|
||||
this.config.maxTokensInput - this.config.maxTokensOutput
|
||||
)
|
||||
throw new Error(GenerateCommitMessageErrorEnum.tooMuchTokens);
|
||||
|
||||
const completion = await this.client.chat.complete(params);
|
||||
|
||||
if (!completion.choices)
|
||||
throw Error('No completion choice available.')
|
||||
|
||||
const message = completion.choices[0].message;
|
||||
|
||||
if (!message || !message.content)
|
||||
throw Error('No completion choice available.')
|
||||
|
||||
return message.content as string;
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
if (
|
||||
axios.isAxiosError<{ error?: { message: string } }>(error) &&
|
||||
error.response?.status === 401
|
||||
) {
|
||||
const mistralError = error.response.data.error;
|
||||
|
||||
if (mistralError) throw new Error(mistralError.message);
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import { OpenAI } from 'openai';
|
||||
import { AiEngine, AiEngineConfig } from './Engine';
|
||||
import { chown } from 'fs';
|
||||
|
||||
interface MLXConfig extends AiEngineConfig {}
|
||||
|
||||
export class MLXEngine implements AiEngine {
|
||||
config: MLXConfig;
|
||||
client: AxiosInstance;
|
||||
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
this.client = axios.create({
|
||||
url: config.baseURL
|
||||
? `${config.baseURL}/${config.apiKey}`
|
||||
: 'http://localhost:8080/v1/chat/completions',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
}
|
||||
|
||||
async generateCommitMessage(
|
||||
messages: Array<OpenAI.Chat.Completions.ChatCompletionMessageParam>):
|
||||
Promise<string | undefined> {
|
||||
const params = {
|
||||
messages,
|
||||
temperature: 0,
|
||||
top_p: 0.1,
|
||||
repetition_penalty: 1.5,
|
||||
stream: false
|
||||
};
|
||||
try {
|
||||
const response = await this.client.post(
|
||||
this.client.getUri(this.config),
|
||||
params
|
||||
);
|
||||
|
||||
const choices = response.data.choices;
|
||||
const message = choices[0].message;
|
||||
|
||||
return message?.content;
|
||||
} catch (err: any) {
|
||||
const message = err.response?.data?.error ?? err.message;
|
||||
throw new Error(`MLX provider error: ${message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user