buroventures-harald-code
Version:
Harald Code - AI-powered coding assistant CLI
342 lines • 12.5 kB
JavaScript
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { CommandKind, } from './types.js';
import { SettingScope } from '../../config/settings.js';
import OpenAI from 'openai';
const COLOR_GREEN = '\u001b[32m';
const COLOR_YELLOW = '\u001b[33m';
const COLOR_RED = '\u001b[31m';
const COLOR_CYAN = '\u001b[36m';
const COLOR_GREY = '\u001b[90m';
const RESET_COLOR = '\u001b[0m';
// Fallback models if API call fails
const FALLBACK_MODELS = [
'gpt-oss-120b',
'llama3.1-8b',
'llama-3.3-70b',
'qwen-3-32b',
'qwen-3-235b-a22b-instruct-2507',
'llama-4-scout-17b-16e-instruct',
'llama-4-maverick-17b-128e-instruct',
];
const DEFAULT_MODEL = 'gpt-oss-120b';
/**
* Fetch available models from Cerebras API
*/
async function fetchAvailableModels() {
try {
const apiKey = process.env.CEREBRAS_API_KEY || process.env.OPENAI_API_KEY;
if (!apiKey) {
return FALLBACK_MODELS;
}
const baseURL = process.env.CEREBRAS_BASE_URL || process.env.OPENAI_BASE_URL || 'https://api.cerebras.ai/v1';
const client = new OpenAI({
apiKey,
baseURL,
timeout: 5000, // 5 second timeout for model listing
});
const response = await client.models.list();
const models = response.data
.map((model) => model.id)
.sort();
return models.length > 0 ? models : FALLBACK_MODELS;
}
catch (error) {
console.warn('Failed to fetch models from Cerebras API, using fallback list:', error);
return FALLBACK_MODELS;
}
}
/**
* Get model details from Cerebras API
*/
async function getModelDetails(modelId) {
try {
const apiKey = process.env.CEREBRAS_API_KEY || process.env.OPENAI_API_KEY;
if (!apiKey) {
return null;
}
const baseURL = process.env.CEREBRAS_BASE_URL || process.env.OPENAI_BASE_URL || 'https://api.cerebras.ai/v1';
const client = new OpenAI({
apiKey,
baseURL,
timeout: 5000,
});
const model = await client.models.retrieve(modelId);
return model;
}
catch (error) {
return null;
}
}
/**
* Show current model configuration
*/
const showCurrentModel = async (context) => {
const { config } = context.services;
if (!config) {
return {
type: 'message',
messageType: 'error',
content: 'Config not loaded.',
};
}
const settings = context.services.settings.merged;
// Get current model from various sources in priority order
const currentModel = config.getModel() ||
settings?.model ||
process.env.CEREBRAS_MODEL ||
process.env.OPENAI_MODEL ||
DEFAULT_MODEL;
const envModel = process.env.CEREBRAS_MODEL || process.env.OPENAI_MODEL;
const settingsModel = settings?.model;
let message = `${COLOR_GREEN}Current Model Configuration${RESET_COLOR}\n\n`;
message += `${COLOR_CYAN}Active Model:${RESET_COLOR} ${currentModel}\n\n`;
message += `${COLOR_GREY}Configuration Sources:${RESET_COLOR}\n`;
message += `• Settings file: ${settingsModel || 'not set'}\n`;
message += `• Environment: ${envModel || 'not set'}\n`;
message += `• Default: ${DEFAULT_MODEL}\n\n`;
// Check if we have API access and validate model
const apiKey = process.env.CEREBRAS_API_KEY || process.env.OPENAI_API_KEY;
if (apiKey) {
message += `${COLOR_GREY}API Status:${RESET_COLOR} ${COLOR_GREEN}Connected${RESET_COLOR}\n`;
// Show loading indicator for API call
context.ui.addItem({
type: 'info',
text: `${COLOR_CYAN}Verifying model with Cerebras API...${RESET_COLOR}`,
}, Date.now());
// Try to get model details from API
const modelDetails = await getModelDetails(currentModel);
if (modelDetails) {
message += `${COLOR_GREEN}✓ Model verified via Cerebras API${RESET_COLOR}\n`;
message += `${COLOR_GREY}Owner: ${modelDetails.owned_by}${RESET_COLOR}\n`;
}
else {
message += `${COLOR_YELLOW}⚠ Model not found in Cerebras API (may still work)${RESET_COLOR}\n`;
}
}
else {
message += `${COLOR_GREY}API Status:${RESET_COLOR} ${COLOR_YELLOW}No API key configured${RESET_COLOR}\n`;
if (FALLBACK_MODELS.includes(currentModel)) {
message += `${COLOR_GREEN}✓ Model is in fallback list${RESET_COLOR}\n`;
}
else {
message += `${COLOR_YELLOW}⚠ Warning: '${currentModel}' is not in the fallback list${RESET_COLOR}\n`;
}
}
message += `\n${COLOR_CYAN}Use '/model list' to see available models or '/model set <model>' to change.${RESET_COLOR}`;
return {
type: 'message',
messageType: 'info',
content: message,
};
};
/**
* List all available models
*/
const listModels = async (context) => {
const { config } = context.services;
if (!config) {
return {
type: 'message',
messageType: 'error',
content: 'Config not loaded.',
};
}
const currentModel = config.getModel() ||
context.services.settings.merged?.model ||
process.env.CEREBRAS_MODEL ||
process.env.OPENAI_MODEL ||
DEFAULT_MODEL;
// Show loading indicator
const apiKey = process.env.CEREBRAS_API_KEY || process.env.OPENAI_API_KEY;
if (apiKey) {
context.ui.addItem({
type: 'info',
text: `${COLOR_CYAN}Loading models from Cerebras API...${RESET_COLOR}`,
}, Date.now());
}
// Fetch available models from API
const availableModels = await fetchAvailableModels();
let message = `${COLOR_GREEN}Available Cerebras Models${RESET_COLOR}`;
if (apiKey) {
message += ` ${COLOR_GREY}(via API)${RESET_COLOR}`;
}
else {
message += ` ${COLOR_GREY}(fallback list)${RESET_COLOR}`;
}
message += `\n\n`;
for (let i = 0; i < availableModels.length; i++) {
const model = availableModels[i];
const isCurrent = model === currentModel;
const marker = isCurrent ? `${COLOR_GREEN}● ` : `${COLOR_GREY}○ `;
const modelColor = isCurrent ? COLOR_GREEN : COLOR_CYAN;
message += `${marker}${modelColor}${model}${RESET_COLOR}`;
if (isCurrent) {
message += ` ${COLOR_YELLOW}(current)${RESET_COLOR}`;
}
// Try to get description from API if available
if (apiKey) {
const modelDetails = await getModelDetails(model);
if (modelDetails) {
message += `\n ${COLOR_GREY}Owner: ${modelDetails.owned_by}${RESET_COLOR}`;
}
}
else {
// Use hardcoded description for fallback models
const description = getModelDescription(model);
if (description) {
message += `\n ${COLOR_GREY}${description}${RESET_COLOR}`;
}
}
message += '\n';
if (i < availableModels.length - 1) {
message += '\n';
}
}
message += `\n\n${COLOR_CYAN}Use '/model set <model>' to change the active model.${RESET_COLOR}`;
if (!apiKey) {
message += `\n${COLOR_YELLOW}💡 Tip: Set CEREBRAS_API_KEY to see the latest available models.${RESET_COLOR}`;
}
return {
type: 'message',
messageType: 'info',
content: message,
};
};
/**
* Set a new model
*/
const setModel = async (context, args) => {
const { config } = context.services;
if (!config) {
return {
type: 'message',
messageType: 'error',
content: 'Config not loaded.',
};
}
const modelName = args.trim();
if (!modelName) {
return {
type: 'message',
messageType: 'error',
content: `${COLOR_RED}Please specify a model name.${RESET_COLOR}\n\n` +
`Usage: /model set <model_name>\n` +
`Example: /model set llama3.1-8b\n\n` +
`Use '/model list' to see available models.`,
};
}
// Show loading indicator for model validation
const apiKey = process.env.CEREBRAS_API_KEY || process.env.OPENAI_API_KEY;
if (apiKey) {
context.ui.addItem({
type: 'info',
text: `${COLOR_CYAN}Validating model with Cerebras API...${RESET_COLOR}`,
}, Date.now());
}
// Validate model name against available models
const availableModels = await fetchAvailableModels();
if (!availableModels.includes(modelName)) {
return {
type: 'message',
messageType: 'error',
content: `${COLOR_RED}Unknown model: '${modelName}'${RESET_COLOR}\n\n` +
`Available models:\n${availableModels.map(m => `• ${m}`).join('\n')}\n\n` +
`Use '/model list' to see detailed information.`,
};
}
try {
const settings = context.services.settings.merged;
if (!settings) {
return {
type: 'message',
messageType: 'error',
content: 'Unable to access settings.',
};
}
// Update the model in settings
context.services.settings.setValue(SettingScope.User, 'model', modelName);
// Also update the config for the current session
config.setModel(modelName);
let message = `${COLOR_GREEN}✓ Model changed successfully!${RESET_COLOR}\n\n`;
message += `${COLOR_CYAN}New model:${RESET_COLOR} ${modelName}\n`;
// Try to get model details from API
const apiKeyForDetails = process.env.CEREBRAS_API_KEY || process.env.OPENAI_API_KEY;
if (apiKeyForDetails) {
context.ui.addItem({
type: 'info',
text: `${COLOR_CYAN}Getting model details...${RESET_COLOR}`,
}, Date.now());
const modelDetails = await getModelDetails(modelName);
if (modelDetails) {
message += `${COLOR_GREY}Owner: ${modelDetails.owned_by}${RESET_COLOR}\n`;
}
}
else {
// Use hardcoded description for fallback
const description = getModelDescription(modelName);
if (description) {
message += `${COLOR_GREY}${description}${RESET_COLOR}\n`;
}
}
message += `\n${COLOR_YELLOW}Note: The model change is now active for new conversations.${RESET_COLOR}`;
return {
type: 'message',
messageType: 'info',
content: message,
};
}
catch (error) {
return {
type: 'message',
messageType: 'error',
content: `Failed to set model: ${error instanceof Error ? error.message : String(error)}`,
};
}
};
/**
* Get description for a model
*/
function getModelDescription(model) {
const descriptions = {
'gpt-oss-120b': 'Default - Best for code generation (120B parameters)',
'llama3.1-8b': 'Fast and efficient (8B parameters)',
'llama-3.3-70b': 'Large model with strong reasoning (70B parameters)',
'qwen-3-32b': 'Qwen 3 model (32B parameters)',
'qwen-3-235b-a22b-instruct-2507': 'Large Qwen 3 instruct model (235B parameters)',
'llama-4-scout-17b-16e-instruct': 'Llama 4 Scout instruct model (17B parameters)',
'llama-4-maverick-17b-128e-instruct': 'Llama 4 Maverick instruct model (17B parameters)',
};
return descriptions[model] || '';
}
export const modelCommand = {
name: 'model',
altNames: ['models', 'm'],
description: 'Manage and switch between Cerebras models',
kind: CommandKind.BUILT_IN,
action: showCurrentModel,
subCommands: [
{
name: 'current',
description: 'Show current model configuration',
kind: CommandKind.BUILT_IN,
action: showCurrentModel,
},
{
name: 'list',
description: 'List all available Cerebras models',
kind: CommandKind.BUILT_IN,
action: listModels,
},
{
name: 'set',
description: 'Set a new model',
kind: CommandKind.BUILT_IN,
action: setModel,
},
],
};
//# sourceMappingURL=modelCommand.js.map