✨ add openrouter AI provider support with comprehensive model list
Add OpenRouterEngine class and integrate it into the configuration system. OpenRouter provides access to 300+ AI models through a unified API, expanding model availability for commit message generation beyond existing providers.
This commit is contained in:
+357
-14
@@ -132,7 +132,339 @@ export const MODEL_LIST = {
|
|||||||
'mistral-moderation-2411',
|
'mistral-moderation-2411',
|
||||||
'mistral-moderation-latest'
|
'mistral-moderation-latest'
|
||||||
],
|
],
|
||||||
deepseek: ['deepseek-chat', 'deepseek-reasoner']
|
|
||||||
|
deepseek: ['deepseek-chat', 'deepseek-reasoner'],
|
||||||
|
|
||||||
|
// OpenRouter available models
|
||||||
|
// input_modalities: 'text'
|
||||||
|
// output_modalities: 'text'
|
||||||
|
// https://openrouter.ai/api/v1/models
|
||||||
|
openrouter: [
|
||||||
|
'openai/gpt-4o-mini', // used by default
|
||||||
|
'01-ai/yi-large',
|
||||||
|
'aetherwiing/mn-starcannon-12b',
|
||||||
|
'agentica-org/deepcoder-14b-preview:free',
|
||||||
|
'ai21/jamba-1.6-large',
|
||||||
|
'ai21/jamba-1.6-mini',
|
||||||
|
'aion-labs/aion-1.0',
|
||||||
|
'aion-labs/aion-1.0-mini',
|
||||||
|
'aion-labs/aion-rp-llama-3.1-8b',
|
||||||
|
'alfredpros/codellama-7b-instruct-solidity',
|
||||||
|
'all-hands/openhands-lm-32b-v0.1',
|
||||||
|
'alpindale/goliath-120b',
|
||||||
|
'alpindale/magnum-72b',
|
||||||
|
'amazon/nova-lite-v1',
|
||||||
|
'amazon/nova-micro-v1',
|
||||||
|
'amazon/nova-pro-v1',
|
||||||
|
'anthracite-org/magnum-v2-72b',
|
||||||
|
'anthracite-org/magnum-v4-72b',
|
||||||
|
'anthropic/claude-2',
|
||||||
|
'anthropic/claude-2.0',
|
||||||
|
'anthropic/claude-2.0:beta',
|
||||||
|
'anthropic/claude-2.1',
|
||||||
|
'anthropic/claude-2.1:beta',
|
||||||
|
'anthropic/claude-2:beta',
|
||||||
|
'anthropic/claude-3-haiku',
|
||||||
|
'anthropic/claude-3-haiku:beta',
|
||||||
|
'anthropic/claude-3-opus',
|
||||||
|
'anthropic/claude-3-opus:beta',
|
||||||
|
'anthropic/claude-3-sonnet',
|
||||||
|
'anthropic/claude-3-sonnet:beta',
|
||||||
|
'anthropic/claude-3.5-haiku',
|
||||||
|
'anthropic/claude-3.5-haiku-20241022',
|
||||||
|
'anthropic/claude-3.5-haiku-20241022:beta',
|
||||||
|
'anthropic/claude-3.5-haiku:beta',
|
||||||
|
'anthropic/claude-3.5-sonnet',
|
||||||
|
'anthropic/claude-3.5-sonnet-20240620',
|
||||||
|
'anthropic/claude-3.5-sonnet-20240620:beta',
|
||||||
|
'anthropic/claude-3.5-sonnet:beta',
|
||||||
|
'anthropic/claude-3.7-sonnet',
|
||||||
|
'anthropic/claude-3.7-sonnet:beta',
|
||||||
|
'anthropic/claude-3.7-sonnet:thinking',
|
||||||
|
'anthropic/claude-opus-4',
|
||||||
|
'anthropic/claude-sonnet-4',
|
||||||
|
'arcee-ai/arcee-blitz',
|
||||||
|
'arcee-ai/caller-large',
|
||||||
|
'arcee-ai/coder-large',
|
||||||
|
'arcee-ai/maestro-reasoning',
|
||||||
|
'arcee-ai/spotlight',
|
||||||
|
'arcee-ai/virtuoso-large',
|
||||||
|
'arcee-ai/virtuoso-medium-v2',
|
||||||
|
'arliai/qwq-32b-arliai-rpr-v1:free',
|
||||||
|
'cognitivecomputations/dolphin-mixtral-8x22b',
|
||||||
|
'cognitivecomputations/dolphin3.0-mistral-24b:free',
|
||||||
|
'cognitivecomputations/dolphin3.0-r1-mistral-24b:free',
|
||||||
|
'cohere/command',
|
||||||
|
'cohere/command-a',
|
||||||
|
'cohere/command-r',
|
||||||
|
'cohere/command-r-03-2024',
|
||||||
|
'cohere/command-r-08-2024',
|
||||||
|
'cohere/command-r-plus',
|
||||||
|
'cohere/command-r-plus-04-2024',
|
||||||
|
'cohere/command-r-plus-08-2024',
|
||||||
|
'cohere/command-r7b-12-2024',
|
||||||
|
'deepseek/deepseek-chat',
|
||||||
|
'deepseek/deepseek-chat-v3-0324',
|
||||||
|
'deepseek/deepseek-chat-v3-0324:free',
|
||||||
|
'deepseek/deepseek-chat:free',
|
||||||
|
'deepseek/deepseek-prover-v2',
|
||||||
|
'deepseek/deepseek-prover-v2:free',
|
||||||
|
'deepseek/deepseek-r1',
|
||||||
|
'deepseek/deepseek-r1-0528',
|
||||||
|
'deepseek/deepseek-r1-0528-qwen3-8b',
|
||||||
|
'deepseek/deepseek-r1-0528-qwen3-8b:free',
|
||||||
|
'deepseek/deepseek-r1-0528:free',
|
||||||
|
'deepseek/deepseek-r1-distill-llama-70b',
|
||||||
|
'deepseek/deepseek-r1-distill-llama-70b:free',
|
||||||
|
'deepseek/deepseek-r1-distill-llama-8b',
|
||||||
|
'deepseek/deepseek-r1-distill-qwen-1.5b',
|
||||||
|
'deepseek/deepseek-r1-distill-qwen-14b',
|
||||||
|
'deepseek/deepseek-r1-distill-qwen-14b:free',
|
||||||
|
'deepseek/deepseek-r1-distill-qwen-32b',
|
||||||
|
'deepseek/deepseek-r1-distill-qwen-32b:free',
|
||||||
|
'deepseek/deepseek-r1-distill-qwen-7b',
|
||||||
|
'deepseek/deepseek-r1-zero:free',
|
||||||
|
'deepseek/deepseek-r1:free',
|
||||||
|
'deepseek/deepseek-v3-base:free',
|
||||||
|
'eleutherai/llemma_7b',
|
||||||
|
'eva-unit-01/eva-llama-3.33-70b',
|
||||||
|
'eva-unit-01/eva-qwen-2.5-32b',
|
||||||
|
'eva-unit-01/eva-qwen-2.5-72b',
|
||||||
|
'featherless/qwerky-72b:free',
|
||||||
|
'google/gemini-2.0-flash-001',
|
||||||
|
'google/gemini-2.0-flash-exp:free',
|
||||||
|
'google/gemini-2.0-flash-lite-001',
|
||||||
|
'google/gemini-2.5-flash-preview',
|
||||||
|
'google/gemini-2.5-flash-preview-05-20',
|
||||||
|
'google/gemini-2.5-flash-preview-05-20:thinking',
|
||||||
|
'google/gemini-2.5-flash-preview:thinking',
|
||||||
|
'google/gemini-2.5-pro-exp-03-25',
|
||||||
|
'google/gemini-2.5-pro-preview',
|
||||||
|
'google/gemini-2.5-pro-preview-05-06',
|
||||||
|
'google/gemini-flash-1.5',
|
||||||
|
'google/gemini-flash-1.5-8b',
|
||||||
|
'google/gemini-pro-1.5',
|
||||||
|
'google/gemma-2-27b-it',
|
||||||
|
'google/gemma-2-9b-it',
|
||||||
|
'google/gemma-2-9b-it:free',
|
||||||
|
'google/gemma-3-12b-it',
|
||||||
|
'google/gemma-3-12b-it:free',
|
||||||
|
'google/gemma-3-1b-it:free',
|
||||||
|
'google/gemma-3-27b-it',
|
||||||
|
'google/gemma-3-27b-it:free',
|
||||||
|
'google/gemma-3-4b-it',
|
||||||
|
'google/gemma-3-4b-it:free',
|
||||||
|
'google/gemma-3n-e4b-it:free',
|
||||||
|
'gryphe/mythomax-l2-13b',
|
||||||
|
'inception/mercury-coder-small-beta',
|
||||||
|
'infermatic/mn-inferor-12b',
|
||||||
|
'inflection/inflection-3-pi',
|
||||||
|
'inflection/inflection-3-productivity',
|
||||||
|
'liquid/lfm-3b',
|
||||||
|
'liquid/lfm-40b',
|
||||||
|
'liquid/lfm-7b',
|
||||||
|
'mancer/weaver',
|
||||||
|
'meta-llama/llama-2-70b-chat',
|
||||||
|
'meta-llama/llama-3-70b-instruct',
|
||||||
|
'meta-llama/llama-3-8b-instruct',
|
||||||
|
'meta-llama/llama-3.1-405b',
|
||||||
|
'meta-llama/llama-3.1-405b-instruct',
|
||||||
|
'meta-llama/llama-3.1-405b:free',
|
||||||
|
'meta-llama/llama-3.1-70b-instruct',
|
||||||
|
'meta-llama/llama-3.1-8b-instruct',
|
||||||
|
'meta-llama/llama-3.1-8b-instruct:free',
|
||||||
|
'meta-llama/llama-3.2-11b-vision-instruct',
|
||||||
|
'meta-llama/llama-3.2-11b-vision-instruct:free',
|
||||||
|
'meta-llama/llama-3.2-1b-instruct',
|
||||||
|
'meta-llama/llama-3.2-1b-instruct:free',
|
||||||
|
'meta-llama/llama-3.2-3b-instruct',
|
||||||
|
'meta-llama/llama-3.2-3b-instruct:free',
|
||||||
|
'meta-llama/llama-3.2-90b-vision-instruct',
|
||||||
|
'meta-llama/llama-3.3-70b-instruct',
|
||||||
|
'meta-llama/llama-3.3-70b-instruct:free',
|
||||||
|
'meta-llama/llama-3.3-8b-instruct:free',
|
||||||
|
'meta-llama/llama-4-maverick',
|
||||||
|
'meta-llama/llama-4-maverick:free',
|
||||||
|
'meta-llama/llama-4-scout',
|
||||||
|
'meta-llama/llama-4-scout:free',
|
||||||
|
'meta-llama/llama-guard-2-8b',
|
||||||
|
'meta-llama/llama-guard-3-8b',
|
||||||
|
'meta-llama/llama-guard-4-12b',
|
||||||
|
'microsoft/mai-ds-r1:free',
|
||||||
|
'microsoft/phi-3-medium-128k-instruct',
|
||||||
|
'microsoft/phi-3-mini-128k-instruct',
|
||||||
|
'microsoft/phi-3.5-mini-128k-instruct',
|
||||||
|
'microsoft/phi-4',
|
||||||
|
'microsoft/phi-4-multimodal-instruct',
|
||||||
|
'microsoft/phi-4-reasoning-plus',
|
||||||
|
'microsoft/phi-4-reasoning-plus:free',
|
||||||
|
'microsoft/phi-4-reasoning:free',
|
||||||
|
'microsoft/wizardlm-2-8x22b',
|
||||||
|
'minimax/minimax-01',
|
||||||
|
'mistralai/codestral-2501',
|
||||||
|
'mistralai/devstral-small',
|
||||||
|
'mistralai/devstral-small:free',
|
||||||
|
'mistralai/magistral-medium-2506',
|
||||||
|
'mistralai/magistral-medium-2506:thinking',
|
||||||
|
'mistralai/magistral-small-2506',
|
||||||
|
'mistralai/ministral-3b',
|
||||||
|
'mistralai/ministral-8b',
|
||||||
|
'mistralai/mistral-7b-instruct',
|
||||||
|
'mistralai/mistral-7b-instruct-v0.1',
|
||||||
|
'mistralai/mistral-7b-instruct-v0.2',
|
||||||
|
'mistralai/mistral-7b-instruct-v0.3',
|
||||||
|
'mistralai/mistral-7b-instruct:free',
|
||||||
|
'mistralai/mistral-large',
|
||||||
|
'mistralai/mistral-large-2407',
|
||||||
|
'mistralai/mistral-large-2411',
|
||||||
|
'mistralai/mistral-medium',
|
||||||
|
'mistralai/mistral-medium-3',
|
||||||
|
'mistralai/mistral-nemo',
|
||||||
|
'mistralai/mistral-nemo:free',
|
||||||
|
'mistralai/mistral-saba',
|
||||||
|
'mistralai/mistral-small',
|
||||||
|
'mistralai/mistral-small-24b-instruct-2501',
|
||||||
|
'mistralai/mistral-small-24b-instruct-2501:free',
|
||||||
|
'mistralai/mistral-small-3.1-24b-instruct',
|
||||||
|
'mistralai/mistral-small-3.1-24b-instruct:free',
|
||||||
|
'mistralai/mistral-tiny',
|
||||||
|
'mistralai/mixtral-8x22b-instruct',
|
||||||
|
'mistralai/mixtral-8x7b-instruct',
|
||||||
|
'mistralai/pixtral-12b',
|
||||||
|
'mistralai/pixtral-large-2411',
|
||||||
|
'moonshotai/kimi-vl-a3b-thinking:free',
|
||||||
|
'moonshotai/moonlight-16b-a3b-instruct:free',
|
||||||
|
'neversleep/llama-3-lumimaid-70b',
|
||||||
|
'neversleep/llama-3-lumimaid-8b',
|
||||||
|
'neversleep/llama-3.1-lumimaid-70b',
|
||||||
|
'neversleep/llama-3.1-lumimaid-8b',
|
||||||
|
'neversleep/noromaid-20b',
|
||||||
|
'nothingiisreal/mn-celeste-12b',
|
||||||
|
'nousresearch/deephermes-3-llama-3-8b-preview:free',
|
||||||
|
'nousresearch/deephermes-3-mistral-24b-preview:free',
|
||||||
|
'nousresearch/hermes-2-pro-llama-3-8b',
|
||||||
|
'nousresearch/hermes-3-llama-3.1-405b',
|
||||||
|
'nousresearch/hermes-3-llama-3.1-70b',
|
||||||
|
'nousresearch/nous-hermes-2-mixtral-8x7b-dpo',
|
||||||
|
'nvidia/llama-3.1-nemotron-70b-instruct',
|
||||||
|
'nvidia/llama-3.1-nemotron-ultra-253b-v1',
|
||||||
|
'nvidia/llama-3.1-nemotron-ultra-253b-v1:free',
|
||||||
|
'nvidia/llama-3.3-nemotron-super-49b-v1',
|
||||||
|
'nvidia/llama-3.3-nemotron-super-49b-v1:free',
|
||||||
|
'open-r1/olympiccoder-32b:free',
|
||||||
|
'openai/chatgpt-4o-latest',
|
||||||
|
'openai/codex-mini',
|
||||||
|
'openai/gpt-3.5-turbo',
|
||||||
|
'openai/gpt-3.5-turbo-0125',
|
||||||
|
'openai/gpt-3.5-turbo-0613',
|
||||||
|
'openai/gpt-3.5-turbo-1106',
|
||||||
|
'openai/gpt-3.5-turbo-16k',
|
||||||
|
'openai/gpt-3.5-turbo-instruct',
|
||||||
|
'openai/gpt-4',
|
||||||
|
'openai/gpt-4-0314',
|
||||||
|
'openai/gpt-4-1106-preview',
|
||||||
|
'openai/gpt-4-turbo',
|
||||||
|
'openai/gpt-4-turbo-preview',
|
||||||
|
'openai/gpt-4.1',
|
||||||
|
'openai/gpt-4.1-mini',
|
||||||
|
'openai/gpt-4.1-nano',
|
||||||
|
'openai/gpt-4.5-preview',
|
||||||
|
'openai/gpt-4o',
|
||||||
|
'openai/gpt-4o-2024-05-13',
|
||||||
|
'openai/gpt-4o-2024-08-06',
|
||||||
|
'openai/gpt-4o-2024-11-20',
|
||||||
|
'openai/gpt-4o-mini-2024-07-18',
|
||||||
|
'openai/gpt-4o-mini-search-preview',
|
||||||
|
'openai/gpt-4o-search-preview',
|
||||||
|
'openai/gpt-4o:extended',
|
||||||
|
'openai/o1',
|
||||||
|
'openai/o1-mini',
|
||||||
|
'openai/o1-mini-2024-09-12',
|
||||||
|
'openai/o1-preview',
|
||||||
|
'openai/o1-preview-2024-09-12',
|
||||||
|
'openai/o1-pro',
|
||||||
|
'openai/o3',
|
||||||
|
'openai/o3-mini',
|
||||||
|
'openai/o3-mini-high',
|
||||||
|
'openai/o3-pro',
|
||||||
|
'openai/o4-mini',
|
||||||
|
'openai/o4-mini-high',
|
||||||
|
'opengvlab/internvl3-14b:free',
|
||||||
|
'opengvlab/internvl3-2b:free',
|
||||||
|
'openrouter/auto',
|
||||||
|
'perplexity/llama-3.1-sonar-large-128k-online',
|
||||||
|
'perplexity/llama-3.1-sonar-small-128k-online',
|
||||||
|
'perplexity/r1-1776',
|
||||||
|
'perplexity/sonar',
|
||||||
|
'perplexity/sonar-deep-research',
|
||||||
|
'perplexity/sonar-pro',
|
||||||
|
'perplexity/sonar-reasoning',
|
||||||
|
'perplexity/sonar-reasoning-pro',
|
||||||
|
'pygmalionai/mythalion-13b',
|
||||||
|
'qwen/qwen-2-72b-instruct',
|
||||||
|
'qwen/qwen-2.5-72b-instruct',
|
||||||
|
'qwen/qwen-2.5-72b-instruct:free',
|
||||||
|
'qwen/qwen-2.5-7b-instruct',
|
||||||
|
'qwen/qwen-2.5-7b-instruct:free',
|
||||||
|
'qwen/qwen-2.5-coder-32b-instruct',
|
||||||
|
'qwen/qwen-2.5-coder-32b-instruct:free',
|
||||||
|
'qwen/qwen-2.5-vl-7b-instruct',
|
||||||
|
'qwen/qwen-2.5-vl-7b-instruct:free',
|
||||||
|
'qwen/qwen-max',
|
||||||
|
'qwen/qwen-plus',
|
||||||
|
'qwen/qwen-turbo',
|
||||||
|
'qwen/qwen-vl-max',
|
||||||
|
'qwen/qwen-vl-plus',
|
||||||
|
'qwen/qwen2.5-vl-32b-instruct',
|
||||||
|
'qwen/qwen2.5-vl-32b-instruct:free',
|
||||||
|
'qwen/qwen2.5-vl-3b-instruct:free',
|
||||||
|
'qwen/qwen2.5-vl-72b-instruct',
|
||||||
|
'qwen/qwen2.5-vl-72b-instruct:free',
|
||||||
|
'qwen/qwen3-14b',
|
||||||
|
'qwen/qwen3-14b:free',
|
||||||
|
'qwen/qwen3-235b-a22b',
|
||||||
|
'qwen/qwen3-235b-a22b:free',
|
||||||
|
'qwen/qwen3-30b-a3b',
|
||||||
|
'qwen/qwen3-30b-a3b:free',
|
||||||
|
'qwen/qwen3-32b',
|
||||||
|
'qwen/qwen3-32b:free',
|
||||||
|
'qwen/qwen3-8b',
|
||||||
|
'qwen/qwen3-8b:free',
|
||||||
|
'qwen/qwq-32b',
|
||||||
|
'qwen/qwq-32b-preview',
|
||||||
|
'qwen/qwq-32b:free',
|
||||||
|
'raifle/sorcererlm-8x22b',
|
||||||
|
'rekaai/reka-flash-3:free',
|
||||||
|
'sao10k/fimbulvetr-11b-v2',
|
||||||
|
'sao10k/l3-euryale-70b',
|
||||||
|
'sao10k/l3-lunaris-8b',
|
||||||
|
'sao10k/l3.1-euryale-70b',
|
||||||
|
'sao10k/l3.3-euryale-70b',
|
||||||
|
'sarvamai/sarvam-m:free',
|
||||||
|
'scb10x/llama3.1-typhoon2-70b-instruct',
|
||||||
|
'sentientagi/dobby-mini-unhinged-plus-llama-3.1-8b',
|
||||||
|
'shisa-ai/shisa-v2-llama3.3-70b:free',
|
||||||
|
'sophosympatheia/midnight-rose-70b',
|
||||||
|
'thedrummer/anubis-pro-105b-v1',
|
||||||
|
'thedrummer/rocinante-12b',
|
||||||
|
'thedrummer/skyfall-36b-v2',
|
||||||
|
'thedrummer/unslopnemo-12b',
|
||||||
|
'thedrummer/valkyrie-49b-v1',
|
||||||
|
'thudm/glm-4-32b',
|
||||||
|
'thudm/glm-4-32b:free',
|
||||||
|
'thudm/glm-z1-32b',
|
||||||
|
'thudm/glm-z1-32b:free',
|
||||||
|
'thudm/glm-z1-rumination-32b',
|
||||||
|
'tngtech/deepseek-r1t-chimera:free',
|
||||||
|
'undi95/remm-slerp-l2-13b',
|
||||||
|
'undi95/toppy-m-7b',
|
||||||
|
'x-ai/grok-2-1212',
|
||||||
|
'x-ai/grok-2-vision-1212',
|
||||||
|
'x-ai/grok-3-beta',
|
||||||
|
'x-ai/grok-3-mini-beta',
|
||||||
|
'x-ai/grok-beta',
|
||||||
|
'x-ai/grok-vision-beta'
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDefaultModel = (provider: string | undefined): string => {
|
const getDefaultModel = (provider: string | undefined): string => {
|
||||||
@@ -151,6 +483,8 @@ const getDefaultModel = (provider: string | undefined): string => {
|
|||||||
return MODEL_LIST.mistral[0];
|
return MODEL_LIST.mistral[0];
|
||||||
case 'deepseek':
|
case 'deepseek':
|
||||||
return MODEL_LIST.deepseek[0];
|
return MODEL_LIST.deepseek[0];
|
||||||
|
case 'openrouter':
|
||||||
|
return MODEL_LIST.openrouter[0];
|
||||||
default:
|
default:
|
||||||
return MODEL_LIST.openai[0];
|
return MODEL_LIST.openai[0];
|
||||||
}
|
}
|
||||||
@@ -340,7 +674,8 @@ export const configValidators = {
|
|||||||
'test',
|
'test',
|
||||||
'flowise',
|
'flowise',
|
||||||
'groq',
|
'groq',
|
||||||
'deepseek'
|
'deepseek',
|
||||||
|
'openrouter'
|
||||||
].includes(value) || value.startsWith('ollama'),
|
].includes(value) || value.startsWith('ollama'),
|
||||||
`${value} is not supported yet, use 'ollama', 'mlx', 'anthropic', 'azure', 'gemini', 'flowise', 'mistral', 'deepseek' or 'openai' (default)`
|
`${value} is not supported yet, use 'ollama', 'mlx', 'anthropic', 'azure', 'gemini', 'flowise', 'mistral', 'deepseek' or 'openai' (default)`
|
||||||
);
|
);
|
||||||
@@ -390,7 +725,8 @@ export enum OCO_AI_PROVIDER_ENUM {
|
|||||||
GROQ = 'groq',
|
GROQ = 'groq',
|
||||||
MISTRAL = 'mistral',
|
MISTRAL = 'mistral',
|
||||||
MLX = 'mlx',
|
MLX = 'mlx',
|
||||||
DEEPSEEK = 'deepseek'
|
DEEPSEEK = 'deepseek',
|
||||||
|
OPENROUTER = 'openrouter'
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ConfigType = {
|
export type ConfigType = {
|
||||||
@@ -658,7 +994,8 @@ function getConfigKeyDetails(key) {
|
|||||||
};
|
};
|
||||||
case CONFIG_KEYS.OCO_DESCRIPTION:
|
case CONFIG_KEYS.OCO_DESCRIPTION:
|
||||||
return {
|
return {
|
||||||
description: 'Postface a message with ~3 sentences description of the changes',
|
description:
|
||||||
|
'Postface a message with ~3 sentences description of the changes',
|
||||||
values: ['true', 'false']
|
values: ['true', 'false']
|
||||||
};
|
};
|
||||||
case CONFIG_KEYS.OCO_EMOJI:
|
case CONFIG_KEYS.OCO_EMOJI:
|
||||||
@@ -668,9 +1005,10 @@ function getConfigKeyDetails(key) {
|
|||||||
};
|
};
|
||||||
case CONFIG_KEYS.OCO_WHY:
|
case CONFIG_KEYS.OCO_WHY:
|
||||||
return {
|
return {
|
||||||
description: 'Output a short description of why the changes were done after the commit message (default: false)',
|
description:
|
||||||
|
'Output a short description of why the changes were done after the commit message (default: false)',
|
||||||
values: ['true', 'false']
|
values: ['true', 'false']
|
||||||
}
|
};
|
||||||
case CONFIG_KEYS.OCO_OMIT_SCOPE:
|
case CONFIG_KEYS.OCO_OMIT_SCOPE:
|
||||||
return {
|
return {
|
||||||
description: 'Do not include a scope in the commit message',
|
description: 'Do not include a scope in the commit message',
|
||||||
@@ -678,7 +1016,8 @@ function getConfigKeyDetails(key) {
|
|||||||
};
|
};
|
||||||
case CONFIG_KEYS.OCO_GITPUSH:
|
case CONFIG_KEYS.OCO_GITPUSH:
|
||||||
return {
|
return {
|
||||||
description: 'Push to git after commit (deprecated). If false, oco will exit after committing',
|
description:
|
||||||
|
'Push to git after commit (deprecated). If false, oco will exit after committing',
|
||||||
values: ['true', 'false']
|
values: ['true', 'false']
|
||||||
};
|
};
|
||||||
case CONFIG_KEYS.OCO_TOKENS_MAX_INPUT:
|
case CONFIG_KEYS.OCO_TOKENS_MAX_INPUT:
|
||||||
@@ -698,13 +1037,14 @@ function getConfigKeyDetails(key) {
|
|||||||
};
|
};
|
||||||
case CONFIG_KEYS.OCO_API_URL:
|
case CONFIG_KEYS.OCO_API_URL:
|
||||||
return {
|
return {
|
||||||
description: 'Custom API URL - may be used to set proxy path to OpenAI API',
|
description:
|
||||||
|
'Custom API URL - may be used to set proxy path to OpenAI API',
|
||||||
values: ["URL string (must start with 'http://' or 'https://')"]
|
values: ["URL string (must start with 'http://' or 'https://')"]
|
||||||
};
|
};
|
||||||
case CONFIG_KEYS.OCO_MESSAGE_TEMPLATE_PLACEHOLDER:
|
case CONFIG_KEYS.OCO_MESSAGE_TEMPLATE_PLACEHOLDER:
|
||||||
return {
|
return {
|
||||||
description: 'Message template placeholder',
|
description: 'Message template placeholder',
|
||||||
values: ["String (must start with $)"]
|
values: ['String (must start with $)']
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
return {
|
return {
|
||||||
@@ -728,7 +1068,6 @@ function printConfigKeyHelp(param) {
|
|||||||
defaultValue = DEFAULT_CONFIG[param];
|
defaultValue = DEFAULT_CONFIG[param];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
console.log(chalk.bold(`\n${param}:`));
|
console.log(chalk.bold(`\n${param}:`));
|
||||||
console.log(chalk.gray(` Description: ${desc}`));
|
console.log(chalk.gray(` Description: ${desc}`));
|
||||||
if (defaultValue !== undefined) {
|
if (defaultValue !== undefined) {
|
||||||
@@ -742,14 +1081,14 @@ function printConfigKeyHelp(param) {
|
|||||||
|
|
||||||
if (Array.isArray(details.values)) {
|
if (Array.isArray(details.values)) {
|
||||||
console.log(chalk.gray(' Accepted values:'));
|
console.log(chalk.gray(' Accepted values:'));
|
||||||
details.values.forEach(value => {
|
details.values.forEach((value) => {
|
||||||
console.log(chalk.gray(` - ${value}`));
|
console.log(chalk.gray(` - ${value}`));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log(chalk.gray(' Accepted values by provider:'));
|
console.log(chalk.gray(' Accepted values by provider:'));
|
||||||
Object.entries(details.values).forEach(([provider, values]) => {
|
Object.entries(details.values).forEach(([provider, values]) => {
|
||||||
console.log(chalk.gray(` ${provider}:`));
|
console.log(chalk.gray(` ${provider}:`));
|
||||||
(values as string[]).forEach(value => {
|
(values as string[]).forEach((value) => {
|
||||||
console.log(chalk.gray(` - ${value}`));
|
console.log(chalk.gray(` - ${value}`));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -765,7 +1104,7 @@ function printAllConfigHelp() {
|
|||||||
if (key in DEFAULT_CONFIG) {
|
if (key in DEFAULT_CONFIG) {
|
||||||
defaultValue = DEFAULT_CONFIG[key];
|
defaultValue = DEFAULT_CONFIG[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(chalk.bold(`\n${key}:`));
|
console.log(chalk.bold(`\n${key}:`));
|
||||||
console.log(chalk.gray(` Description: ${details.description}`));
|
console.log(chalk.gray(` Description: ${details.description}`));
|
||||||
if (defaultValue !== undefined) {
|
if (defaultValue !== undefined) {
|
||||||
@@ -776,7 +1115,11 @@ function printAllConfigHelp() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(chalk.yellow('\nUse "oco config describe [PARAMETER]" to see accepted values and more details for a specific config parameter.'));
|
console.log(
|
||||||
|
chalk.yellow(
|
||||||
|
'\nUse "oco config describe [PARAMETER]" to see accepted values and more details for a specific config parameter.'
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const configCommand = command(
|
export const configCommand = command(
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import OpenAI from 'openai';
|
||||||
|
import { AiEngine, AiEngineConfig } from './Engine';
|
||||||
|
import axios, { AxiosInstance } from 'axios';
|
||||||
|
import { removeContentTags } from '../utils/removeContentTags';
|
||||||
|
|
||||||
|
interface OpenRouterConfig extends AiEngineConfig {}
|
||||||
|
|
||||||
|
export class OpenRouterEngine implements AiEngine {
|
||||||
|
client: AxiosInstance;
|
||||||
|
|
||||||
|
constructor(public config: OpenRouterConfig) {
|
||||||
|
this.client = axios.create({
|
||||||
|
baseURL: 'https://openrouter.ai/api/v1/chat/completions',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${config.apiKey}`,
|
||||||
|
'HTTP-Referer': 'https://github.com/di-sukharev/opencommit',
|
||||||
|
'X-Title': 'OpenCommit',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public generateCommitMessage = async (
|
||||||
|
messages: Array<OpenAI.Chat.Completions.ChatCompletionMessageParam>
|
||||||
|
): Promise<string | null> => {
|
||||||
|
try {
|
||||||
|
const response = await this.client.post('', {
|
||||||
|
model: this.config.model,
|
||||||
|
messages
|
||||||
|
});
|
||||||
|
|
||||||
|
const message = response.data.choices[0].message;
|
||||||
|
let content = message?.content;
|
||||||
|
return removeContentTags(content, 'think');
|
||||||
|
} catch (error) {
|
||||||
|
const err = error as Error;
|
||||||
|
if (
|
||||||
|
axios.isAxiosError<{ error?: { message: string } }>(error) &&
|
||||||
|
error.response?.status === 401
|
||||||
|
) {
|
||||||
|
const openRouterError = error.response.data.error;
|
||||||
|
|
||||||
|
if (openRouterError) throw new Error(openRouterError.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
+10
-4
@@ -11,14 +11,15 @@ import { TestAi, TestMockType } from '../engine/testAi';
|
|||||||
import { GroqEngine } from '../engine/groq';
|
import { GroqEngine } from '../engine/groq';
|
||||||
import { MLXEngine } from '../engine/mlx';
|
import { MLXEngine } from '../engine/mlx';
|
||||||
import { DeepseekEngine } from '../engine/deepseek';
|
import { DeepseekEngine } from '../engine/deepseek';
|
||||||
|
import { OpenRouterEngine } from '../engine/openrouter';
|
||||||
|
|
||||||
export function parseCustomHeaders(headers: any): Record<string, string> {
|
export function parseCustomHeaders(headers: any): Record<string, string> {
|
||||||
let parsedHeaders = {};
|
let parsedHeaders = {};
|
||||||
|
|
||||||
if (!headers) {
|
if (!headers) {
|
||||||
return parsedHeaders;
|
return parsedHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (typeof headers === 'object' && !Array.isArray(headers)) {
|
if (typeof headers === 'object' && !Array.isArray(headers)) {
|
||||||
parsedHeaders = headers;
|
parsedHeaders = headers;
|
||||||
@@ -26,9 +27,11 @@ export function parseCustomHeaders(headers: any): Record<string, string> {
|
|||||||
parsedHeaders = JSON.parse(headers);
|
parsedHeaders = JSON.parse(headers);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('Invalid OCO_API_CUSTOM_HEADERS format, ignoring custom headers');
|
console.warn(
|
||||||
|
'Invalid OCO_API_CUSTOM_HEADERS format, ignoring custom headers'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsedHeaders;
|
return parsedHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,6 +81,9 @@ export function getEngine(): AiEngine {
|
|||||||
case OCO_AI_PROVIDER_ENUM.DEEPSEEK:
|
case OCO_AI_PROVIDER_ENUM.DEEPSEEK:
|
||||||
return new DeepseekEngine(DEFAULT_CONFIG);
|
return new DeepseekEngine(DEFAULT_CONFIG);
|
||||||
|
|
||||||
|
case OCO_AI_PROVIDER_ENUM.OPENROUTER:
|
||||||
|
return new OpenRouterEngine(DEFAULT_CONFIG);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return new OpenAiEngine(DEFAULT_CONFIG);
|
return new OpenAiEngine(DEFAULT_CONFIG);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user