voyageai-cli
Version:
CLI for Voyage AI embeddings, reranking, and MongoDB Atlas Vector Search
155 lines (147 loc) • 4.36 kB
JavaScript
;
/**
* Global config steps for vai init when ~/.vai/config.json is missing or incomplete.
* Collects: Voyage API key (required), optional MongoDB URI, optional LLM (provider, key, model).
*/
const { PROVIDER_DEFAULTS, PROVIDER_MODELS, listOllamaModels } = require('./llm');
let _ollamaModels = null;
let _ollamaChecked = false;
async function getProviderOptions() {
if (!_ollamaChecked) {
_ollamaChecked = true;
try {
_ollamaModels = await listOllamaModels({ timeoutMs: 2000 });
} catch {
_ollamaModels = [];
}
}
const ollamaAvailable = _ollamaModels && _ollamaModels.length > 0;
return [
{ value: 'anthropic', label: 'Anthropic (Claude)', hint: 'Best instruction following' },
{ value: 'openai', label: 'OpenAI (GPT-4o)', hint: 'Broad model selection' },
{
value: 'ollama',
label: ollamaAvailable
? `Ollama (${_ollamaModels.length} model${_ollamaModels.length === 1 ? '' : 's'} installed)`
: 'Ollama (local — not detected)',
hint: ollamaAvailable ? 'Free, fully private' : 'Requires ollama running locally',
},
];
}
async function getModelOptions(answers) {
const provider = answers.llmProvider;
if (!provider) return [];
if (provider === 'ollama') {
const models = _ollamaModels || [];
if (models.length === 0) {
return [{ value: 'llama3.1', label: 'llama3.1', hint: 'default (ollama pull llama3.1)' }];
}
return models.map((m) => ({
value: m.id,
label: m.name,
hint: [m.parameterSize, m.size].filter(Boolean).join(' — ') || undefined,
}));
}
const cloudModels = PROVIDER_MODELS[provider] || [];
return cloudModels.map((m) => ({
value: m.id,
label: m.name,
hint: m.context ? `context: ${m.context}` : undefined,
}));
}
/**
* Steps for global setup: Voyage API key (required), optional MongoDB, optional LLM.
* Used by vai init when API key is not configured.
*/
const globalSetupSteps = [
{
id: 'apiKey',
label: 'Voyage AI API key',
type: 'password',
required: true,
placeholder: 'pa-... or al-...',
validate: (value) => {
if (!value || value.trim().length < 10) {
return 'API key looks too short. Get one at https://dash.voyageai.com/api-keys';
}
return true;
},
group: 'API & connections',
},
{
id: 'wantMongo',
label: 'Configure MongoDB? (for store/search/chat)',
type: 'confirm',
defaultValue: false,
group: 'API & connections',
},
{
id: 'mongodbUri',
label: 'MongoDB connection URI',
type: 'password',
required: false,
placeholder: 'mongodb+srv://user:pass@cluster.mongodb.net/',
skip: (answers) => !answers.wantMongo,
validate: (value) => {
if (value && !value.startsWith('mongodb')) {
return 'URI should start with mongodb:// or mongodb+srv://';
}
return true;
},
group: 'API & connections',
},
{
id: 'wantLlm',
label: 'Configure an LLM for chat/RAG? (optional)',
type: 'confirm',
defaultValue: false,
group: 'LLM (optional)',
},
{
id: 'llmProvider',
label: 'LLM provider',
type: 'select',
options: () => getProviderOptions(),
required: false,
skip: (answers) => !answers.wantLlm,
group: 'LLM (optional)',
},
{
id: 'llmApiKey',
label: 'LLM API key',
type: 'password',
required: false,
placeholder: 'sk-...',
skip: (answers) => !answers.wantLlm || answers.llmProvider === 'ollama',
validate: (value) => {
if (value && value.length < 8) return 'API key looks too short';
return true;
},
group: 'LLM (optional)',
},
{
id: 'llmModel',
label: 'LLM model',
type: 'select',
options: (answers) => getModelOptions(answers),
getDefault: (answers) => (answers.llmProvider ? PROVIDER_DEFAULTS[answers.llmProvider] : null),
required: false,
skip: (answers) => !answers.wantLlm,
group: 'LLM (optional)',
},
{
id: 'llmBaseUrl',
label: 'Ollama URL',
type: 'text',
defaultValue: 'http://localhost:11434',
placeholder: 'http://localhost:11434',
required: false,
skip: (answers) => !answers.wantLlm || answers.llmProvider !== 'ollama',
group: 'LLM (optional)',
},
];
module.exports = {
globalSetupSteps,
getProviderOptions,
getModelOptions,
};