UNPKG

@nanocollective/nanocoder

Version:

A local-first CLI coding agent that brings the power of agentic coding tools like Claude Code and Gemini CLI to local models or controlled APIs like OpenRouter

178 lines 5.97 kB
/** * Fetch models from cloud LLM providers * - Anthropic: GET /v1/models with X-Api-Key header * - OpenAI: GET /v1/models with Authorization: Bearer header * - Mistral: GET /v1/models with Authorization: Bearer header * - GitHub: GET /catalog/models with Bearer token and X-GitHub-Api-Version header */ const CLOUD_PROVIDERS = { anthropic: { endpoint: 'https://api.anthropic.com/v1/models', getHeaders: apiKey => ({ 'X-Api-Key': apiKey, 'anthropic-version': '2023-06-01', Accept: 'application/json', }), }, openai: { endpoint: 'https://api.openai.com/v1/models', getHeaders: apiKey => ({ Authorization: `Bearer ${apiKey}`, Accept: 'application/json', }), }, mistral: { endpoint: 'https://api.mistral.ai/v1/models', getHeaders: apiKey => ({ Authorization: `Bearer ${apiKey}`, Accept: 'application/json', }), }, github: { endpoint: 'https://models.github.ai/catalog/models', getHeaders: apiKey => ({ Accept: 'application/vnd.github+json', Authorization: `Bearer ${apiKey}`, 'X-GitHub-Api-Version': '2022-11-28', }), }, }; /** * Fetch available models from a cloud LLM provider * @param providerType The cloud provider type ('anthropic', 'openai', 'mistral', 'github') * @param apiKey The API key for authentication * @param options Optional settings (timeoutMs, debug) */ export async function fetchCloudModels(providerType, apiKey, options = {}) { const { timeoutMs = 10000, debug = false } = options; const log = (message) => { if (debug) { console.log(`[fetch-cloud-models] ${message}`); } }; const providerConfig = CLOUD_PROVIDERS[providerType]; if (!providerConfig) { return { success: false, models: [], error: `Unknown cloud provider: ${providerType}`, }; } if (!apiKey || !apiKey.trim()) { return { success: false, models: [], error: 'API key is required', }; } try { log(`Fetching models from ${providerType}: ${providerConfig.endpoint}`); const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeoutMs); let data; try { const response = await fetch(providerConfig.endpoint, { method: 'GET', signal: controller.signal, headers: providerConfig.getHeaders(apiKey), }); if (!response.ok) { log(`Server error: ${response.status} ${response.statusText}`); // Provide helpful error messages for common cases if (response.status === 401) { return { success: false, models: [], error: 'Invalid API key', }; } if (response.status === 403) { return { success: false, models: [], error: 'API key does not have permission to list models', }; } return { success: false, models: [], error: `API returned ${response.status}: ${response.statusText}`, }; } log(`Response OK, parsing JSON...`); data = (await response.json()); log(`JSON parsed successfully`); } finally { clearTimeout(timeoutId); } let modelArray; if (providerType === 'github') { // GitHub returns array directly if (!Array.isArray(data)) { return { success: false, models: [], error: 'Invalid response format from API', }; } modelArray = data; } else { // Other providers return { data: [...] } if (!data.data || !Array.isArray(data.data)) { return { success: false, models: [], error: 'Invalid response format from API', }; } modelArray = data.data; } // Parse models - use name (GitHub) or display_name (Anthropic), otherwise id const models = modelArray .filter(m => m && typeof m.id === 'string' && m.id.trim()) .map(m => ({ id: m.id.trim(), name: m.name || m.display_name || m.id.trim(), })) .sort((a, b) => a.name.localeCompare(b.name)); log(`Found ${models.length} models (sorted)`); if (models.length === 0) { return { success: false, models: [], error: 'No models found for this API key', }; } return { success: true, models, }; } catch (err) { if (err instanceof Error) { if (err.name === 'AbortError') { log(`Request timed out after ${timeoutMs}ms`); return { success: false, models: [], error: 'Connection timed out', }; } log(`Error: ${err.message}`); return { success: false, models: [], error: err.message, }; } log(`Unknown error occurred`); return { success: false, models: [], error: 'Unknown error occurred', }; } } //# sourceMappingURL=fetch-cloud-models.js.map