AG X v2.0.3 - Antigravity fork with multi-provider support
Features: - Welcome screen on first run (provider choice before LS starts) - 15+ AI providers (Google Gemini, OpenAI, Anthropic, DeepSeek, Ollama, etc.) - Provider config syncs to endpoints.json for translation proxy - Built-in Node.js translation proxy for non-native backends - Auto-update support, tray integration, URI scheme handler
This commit is contained in:
169
dist/providerSettings.js
vendored
Normal file
169
dist/providerSettings.js
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.openProviderSettings = openProviderSettings;
|
||||
exports.closeProviderSettings = closeProviderSettings;
|
||||
const electron_1 = require("electron");
|
||||
const path_1 = require("path");
|
||||
let settingsWindow = null;
|
||||
function openProviderSettings(providerService) {
|
||||
if (settingsWindow) {
|
||||
settingsWindow.show();
|
||||
settingsWindow.focus();
|
||||
return;
|
||||
}
|
||||
settingsWindow = new electron_1.BrowserWindow({
|
||||
width: 820,
|
||||
height: 720,
|
||||
title: 'AI Provider Settings',
|
||||
resizable: true,
|
||||
minimizable: true,
|
||||
maximizable: true,
|
||||
backgroundColor: '#1a1a2e',
|
||||
titleBarStyle: 'hidden',
|
||||
titleBarOverlay: {
|
||||
color: '#16213e',
|
||||
symbolColor: '#e0e0e0',
|
||||
height: 36,
|
||||
},
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false,
|
||||
enableRemoteModule: false,
|
||||
},
|
||||
});
|
||||
settingsWindow.loadFile(path_1.join(__dirname, 'provider', 'settings.html'));
|
||||
settingsWindow.on('closed', () => {
|
||||
settingsWindow = null;
|
||||
});
|
||||
// Register IPC handlers for provider settings
|
||||
electron_1.ipcMain.handle('provider:get-config', async () => {
|
||||
return {
|
||||
activeProvider: providerService.getActiveProvider(),
|
||||
providers: providerService.getAllProviders(),
|
||||
};
|
||||
});
|
||||
electron_1.ipcMain.handle('provider:save', async (_event, settings) => {
|
||||
providerService.setActiveProvider(settings.activeProvider);
|
||||
providerService.updateProviderConfig(settings.activeProvider, settings.providerConfig);
|
||||
// Sync to endpoints.json so the LS proxy uses this provider on next restart
|
||||
try {
|
||||
const os = require('os');
|
||||
const fs = require('fs');
|
||||
const pathMod = require('path');
|
||||
const home = os.homedir();
|
||||
const endpointsPath = pathMod.join(home, '.codex', 'endpoints.json');
|
||||
const activePath = pathMod.join(home, '.codex', '.active-endpoint.json');
|
||||
const activeProvider = providerService.getActiveProvider();
|
||||
const providerConfig = providerService.getProviderConfig(activeProvider);
|
||||
if (providerConfig) {
|
||||
let endpointsData = { default: '', endpoints: [] };
|
||||
if (fs.existsSync(endpointsPath)) {
|
||||
try { endpointsData = JSON.parse(fs.readFileSync(endpointsPath, 'utf8')); } catch(e) {}
|
||||
}
|
||||
const endpointName = 'AG X: ' + (providerConfig.name || activeProvider);
|
||||
const existingIdx = endpointsData.endpoints.findIndex(e => e.name === endpointName);
|
||||
const endpoint = {
|
||||
name: endpointName,
|
||||
backend_type: providerConfig.backendType || 'openai-compat',
|
||||
base_url: providerConfig.apiUrl || '',
|
||||
api_key: providerConfig.apiKey || '',
|
||||
default_model: providerConfig.model || providerConfig.defaultModel || '',
|
||||
models: providerConfig.models || [],
|
||||
provider_preset: 'AG X',
|
||||
};
|
||||
if (existingIdx >= 0) {
|
||||
endpointsData.endpoints[existingIdx] = endpoint;
|
||||
} else {
|
||||
endpointsData.endpoints.push(endpoint);
|
||||
}
|
||||
endpointsData.default = endpointName;
|
||||
fs.writeFileSync(endpointsPath, JSON.stringify(endpointsData, null, 2), 'utf-8');
|
||||
fs.writeFileSync(activePath, JSON.stringify({ active: endpointName }, null, 2), 'utf-8');
|
||||
console.log('[Settings] Provider synced to endpoints.json:', endpointName);
|
||||
}
|
||||
} catch(e) { console.error('[Settings] Failed to sync:', e); }
|
||||
// Notify welcome screen (if waiting) that settings are saved
|
||||
electron_1.ipcMain.emit('provider:settings-saved');
|
||||
return { success: true, needsRestart: true };
|
||||
});
|
||||
electron_1.ipcMain.handle('provider:reset', async () => {
|
||||
const fs = require("fs");
|
||||
const configPath = providerService.configPath;
|
||||
if (fs.existsSync(configPath)) {
|
||||
fs.unlinkSync(configPath);
|
||||
}
|
||||
// Reload defaults
|
||||
providerService.config = providerService.loadConfig();
|
||||
return { success: true };
|
||||
});
|
||||
electron_1.ipcMain.handle('provider:save-advanced', async (_event, settings) => {
|
||||
// Store advanced settings
|
||||
const fs = require("fs");
|
||||
const advancedPath = providerService.configPath.replace('.json', '_advanced.json');
|
||||
fs.writeFileSync(advancedPath, JSON.stringify(settings, null, 2), 'utf-8');
|
||||
return { success: true };
|
||||
});
|
||||
electron_1.ipcMain.on('provider:close-settings', () => {
|
||||
closeProviderSettings();
|
||||
});
|
||||
electron_1.ipcMain.handle('provider:test-connection', async (_event, testConfig) => {
|
||||
return testProviderConnection(testConfig);
|
||||
});
|
||||
}
|
||||
function closeProviderSettings() {
|
||||
if (settingsWindow) {
|
||||
settingsWindow.close();
|
||||
settingsWindow = null;
|
||||
}
|
||||
}
|
||||
async function testProviderConnection(testConfig) {
|
||||
const http = require("http");
|
||||
const https = require("https");
|
||||
const url = new URL(testConfig.apiUrl || 'https://api.openai.com');
|
||||
const isHttps = url.protocol === 'https:';
|
||||
const httpModule = isHttps ? https : http;
|
||||
return new Promise((resolve) => {
|
||||
const options = {
|
||||
hostname: url.hostname,
|
||||
port: url.port || (isHttps ? 443 : 80),
|
||||
path: testConfig.provider === 'ollama' ? '/api/tags' : '/',
|
||||
method: 'GET',
|
||||
timeout: 10000,
|
||||
headers: {},
|
||||
};
|
||||
if (testConfig.apiKey) {
|
||||
if (testConfig.provider === 'anthropic') {
|
||||
options.headers['x-api-key'] = testConfig.apiKey;
|
||||
options.headers['anthropic-version'] = '2023-06-01';
|
||||
} else {
|
||||
options.headers['Authorization'] = `Bearer ${testConfig.apiKey}`;
|
||||
}
|
||||
}
|
||||
const req = httpModule.request(options, (res) => {
|
||||
let body = '';
|
||||
res.on('data', (chunk) => (body += chunk));
|
||||
res.on('end', () => {
|
||||
if (res.statusCode && res.statusCode < 500) {
|
||||
resolve({
|
||||
success: true,
|
||||
message: `HTTP ${res.statusCode} — Server reachable. Model: ${testConfig.model || 'default'}`,
|
||||
});
|
||||
}
|
||||
else {
|
||||
resolve({
|
||||
success: false,
|
||||
error: `HTTP ${res.statusCode}: ${body.substring(0, 200)}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
req.on('error', (err) => {
|
||||
resolve({ success: false, error: err.message });
|
||||
});
|
||||
req.on('timeout', () => {
|
||||
req.destroy();
|
||||
resolve({ success: false, error: 'Connection timed out after 10s' });
|
||||
});
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user