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:
admin
2026-05-22 23:20:10 +04:00
Unverified
commit 43e2a2f78f
46 changed files with 7719 additions and 0 deletions

358
dist/services/providerService.js vendored Normal file
View File

@@ -0,0 +1,358 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProviderService = exports.ProviderType = void 0;
const fs = require("fs");
const path = require("path");
const os = require("os");
var ProviderType;
(function (ProviderType) {
ProviderType["GOOGLE_GEMINI"] = "google_gemini";
ProviderType["OPENAI"] = "openai";
ProviderType["ANTHROPIC"] = "anthropic";
ProviderType["Z_AI"] = "z_ai";
ProviderType["OPENCODE_ZEN"] = "opencode_zen";
ProviderType["OPENCODE_GO"] = "opencode_go";
ProviderType["OPENCODE_ZEN_ANTHROPIC"] = "opencode_zen_anthropic";
ProviderType["OPENCODE_GO_ANTHROPIC"] = "opencode_go_anthropic";
ProviderType["CROF_AI"] = "crof_ai";
ProviderType["NVIDIA_NIM"] = "nvidia_nim";
ProviderType["KILO_AI"] = "kilo_ai";
ProviderType["COMMAND_CODE"] = "command_code";
ProviderType["OPENROUTER"] = "openrouter";
ProviderType["OPENADAPTER"] = "openadapter";
ProviderType["DEEPSEEK"] = "deepseek";
ProviderType["OLLAMA"] = "ollama";
ProviderType["TOGETHER"] = "together";
ProviderType["GROQ"] = "groq";
ProviderType["CUSTOM"] = "custom";
})(ProviderType = exports.ProviderType || (exports.ProviderType = {}));
const PREDEFINED_PROVIDERS = {
[ProviderType.GOOGLE_GEMINI]: {
name: 'Google Gemini (OAuth)',
icon: '🔮',
description: 'Built-in Gemini via Google OAuth — zero config',
apiUrl: 'https://daily-cloudcode-pa.sandbox.googleapis.com',
backendType: 'gemini-native',
requiresApiKey: false,
apiKeyHint: '',
models: ['gemini-2.5-pro', 'gemini-2.5-flash', 'gemini-2.0-flash', 'gemini-3-flash-preview', 'gemini-3-pro-preview'],
defaultModel: 'gemini-2.5-pro',
},
[ProviderType.OPENAI]: {
name: 'OpenAI',
icon: '🟢',
description: 'GPT models via Responses API',
apiUrl: 'https://api.openai.com/v1',
backendType: 'native',
requiresApiKey: true,
apiKeyHint: 'OpenAI API Key (sk-...)',
models: ['gpt-4o', 'gpt-4o-mini', 'o1', 'o1-mini', 'o3', 'o3-mini'],
defaultModel: 'gpt-4o',
},
[ProviderType.ANTHROPIC]: {
name: 'Anthropic',
icon: '🟣',
description: 'Claude models via Messages API',
apiUrl: 'https://api.anthropic.com',
backendType: 'anthropic',
requiresApiKey: true,
apiKeyHint: 'Anthropic API Key (sk-ant-...)',
models: ['claude-sonnet-4-20250514', 'claude-3-5-sonnet-20241022', 'claude-3-5-haiku-20241022', 'claude-3-opus-20240229'],
defaultModel: 'claude-sonnet-4-20250514',
},
[ProviderType.Z_AI]: {
name: 'Z.AI Coding',
icon: '🅩',
description: 'GLM & Z models via Z.AI',
apiUrl: 'https://api.z.ai/api/coding/paas/v4',
backendType: 'openai-compat',
requiresApiKey: true,
apiKeyHint: 'Z.AI API Key',
models: ['glm-5.1', 'glm-4.7', 'GLM-4-Plus', 'GLM-4-Long', 'GLM-4-Flash', 'GLM-4-FlashX', 'GLM-Z1-Flash'],
defaultModel: 'glm-5.1',
},
[ProviderType.OPENCODE_ZEN]: {
name: 'OpenCode Zen',
icon: '🧘',
description: 'Multi-model via OpenCode Zen (OpenAI-compat)',
apiUrl: 'https://opencode.ai/zen/v1',
backendType: 'openai-compat',
requiresApiKey: true,
apiKeyHint: 'OpenCode API Key',
models: ['glm-5.1', 'glm-5', 'kimi-k2.5', 'kimi-k2.6', 'minimax-m2.7', 'minimax-m2.5', 'minimax-m2.5-free', 'deepseek-v4-flash-free', 'nemotron-3-super-free', 'qwen3.6-plus', 'qwen3.5-plus', 'big-pickle'],
defaultModel: 'glm-5.1',
},
[ProviderType.OPENCODE_GO]: {
name: 'OpenCode Go',
icon: '🚀',
description: 'Multi-model via OpenCode Go (OpenAI-compat)',
apiUrl: 'https://opencode.ai/zen/go/v1',
backendType: 'openai-compat',
requiresApiKey: true,
apiKeyHint: 'OpenCode API Key',
models: ['glm-5.1', 'glm-5', 'kimi-k2.5', 'kimi-k2.6', 'mimo-v2.5', 'mimo-v2.5-pro', 'minimax-m2.7', 'minimax-m2.5', 'qwen3.6-plus', 'qwen3.5-plus', 'deepseek-v4-pro', 'deepseek-v4-flash'],
defaultModel: 'glm-5.1',
},
[ProviderType.OPENCODE_ZEN_ANTHROPIC]: {
name: 'OpenCode Zen (Anthropic)',
icon: '🧘',
description: 'Claude models via OpenCode Zen',
apiUrl: 'https://opencode.ai/zen/v1',
backendType: 'anthropic',
requiresApiKey: true,
apiKeyHint: 'OpenCode API Key',
models: ['claude-opus-4-7', 'claude-opus-4-6', 'claude-opus-4-5', 'claude-opus-4-1', 'claude-sonnet-4-6', 'claude-sonnet-4-5', 'claude-sonnet-4', 'claude-haiku-4-5', 'claude-3-5-haiku'],
defaultModel: 'claude-sonnet-4-6',
},
[ProviderType.OPENCODE_GO_ANTHROPIC]: {
name: 'OpenCode Go (Anthropic)',
icon: '🚀',
description: 'Claude models via OpenCode Go',
apiUrl: 'https://opencode.ai/zen/go/v1',
backendType: 'anthropic',
requiresApiKey: true,
apiKeyHint: 'OpenCode API Key',
models: ['minimax-m2.7', 'minimax-m2.5'],
defaultModel: 'minimax-m2.7',
},
[ProviderType.CROF_AI]: {
name: 'Crof.ai',
icon: '🌐',
description: 'OpenAI-compatible models via Crof.ai',
apiUrl: 'https://crof.ai/v1',
backendType: 'openai-compat',
requiresApiKey: true,
apiKeyHint: 'Crof.ai API Key',
models: [],
defaultModel: '',
},
[ProviderType.NVIDIA_NIM]: {
name: 'NVIDIA NIM',
icon: '💚',
description: 'NVIDIA accelerated inference models',
apiUrl: 'https://integrate.api.nvidia.com/v1',
backendType: 'openai-compat',
requiresApiKey: true,
apiKeyHint: 'NVIDIA API Key (nvapi-...)',
models: [],
defaultModel: '',
},
[ProviderType.KILO_AI]: {
name: 'Kilo.ai Gateway',
icon: '⚖️',
description: 'Multi-provider via Kilo.ai',
apiUrl: 'https://api.kilo.ai/api/gateway',
backendType: 'openai-compat',
requiresApiKey: true,
apiKeyHint: 'Kilo.ai API Key',
models: [],
defaultModel: '',
},
[ProviderType.COMMAND_CODE]: {
name: 'Command Code',
icon: '⌘',
description: '20+ models via Command Code API',
apiUrl: 'https://api.commandcode.ai',
backendType: 'command-code',
requiresApiKey: true,
apiKeyHint: 'Command Code API Key',
ccVersion: '0.26.8',
models: [
'deepseek/deepseek-v4-flash', 'deepseek/deepseek-v4-pro',
'anthropic:claude-sonnet-4-6', 'anthropic:claude-haiku-4-5-20251001',
'anthropic:claude-opus-4-7', 'anthropic:claude-opus-4-6',
'openai:gpt-5.5', 'openai:gpt-5.4', 'openai:gpt-5.4-mini', 'openai:gpt-5.3-codex',
'moonshotai/Kimi-K2.6', 'moonshotai/Kimi-K2.5',
'zai-org/GLM-5.1', 'zai-org/GLM-5',
'MiniMaxAI/MiniMax-M2.7', 'MiniMaxAI/MiniMax-M2.5',
'Qwen/Qwen3.6-Max-Preview', 'Qwen/Qwen3.6-Plus',
'stepfun/Step-3.5-Flash', 'google/gemini-3.1-flash-lite',
],
defaultModel: 'deepseek/deepseek-v4-flash',
},
[ProviderType.OPENROUTER]: {
name: 'OpenRouter',
icon: '🔀',
description: 'Route to hundreds of models via OpenRouter',
apiUrl: 'https://openrouter.ai/api/v1',
backendType: 'openai-compat',
requiresApiKey: true,
apiKeyHint: 'OpenRouter API Key (sk-or-...)',
models: [],
defaultModel: '',
},
[ProviderType.OPENADAPTER]: {
name: 'OpenAdapter',
icon: '🔌',
description: 'Free/proxy models via OpenAdapter',
apiUrl: 'https://api.openadapter.in/v1',
backendType: 'openai-compat',
requiresApiKey: true,
apiKeyHint: 'OpenAdapter API Key',
models: ['0G-DeepSeek-V3', '0G-DeepSeek-v4-Pro', '0G-GLM-5', '0G-GLM-5.1', '0G-Qwen3.6', '0G-Qwen-VL'],
defaultModel: '0G-DeepSeek-v4-Pro',
},
[ProviderType.DEEPSEEK]: {
name: 'DeepSeek',
icon: '🔍',
description: 'DeepSeek models directly',
apiUrl: 'https://api.deepseek.com/v1',
backendType: 'openai-compat',
requiresApiKey: true,
apiKeyHint: 'DeepSeek API Key',
models: ['deepseek-chat', 'deepseek-reasoner'],
defaultModel: 'deepseek-chat',
},
[ProviderType.OLLAMA]: {
name: 'Ollama (Local)',
icon: '🦙',
description: 'Run models locally with Ollama',
apiUrl: 'http://127.0.0.1:11434',
backendType: 'openai-compat',
requiresApiKey: false,
apiKeyHint: '',
models: ['llama3.1', 'llama3', 'codellama', 'mistral', 'mixtral', 'deepseek-coder', 'qwen2.5-coder'],
defaultModel: 'llama3.1',
},
[ProviderType.TOGETHER]: {
name: 'Together AI',
icon: '🤝',
description: 'Open-source models via Together',
apiUrl: 'https://api.together.xyz/v1',
backendType: 'openai-compat',
requiresApiKey: true,
apiKeyHint: 'Together API Key',
models: [],
defaultModel: '',
},
[ProviderType.GROQ]: {
name: 'Groq',
icon: '⚡',
description: 'Ultra-fast inference via Groq',
apiUrl: 'https://api.groq.com/openai/v1',
backendType: 'openai-compat',
requiresApiKey: true,
apiKeyHint: 'Groq API Key (gsk_...)',
models: [],
defaultModel: '',
},
[ProviderType.CUSTOM]: {
name: 'Custom Provider',
icon: '⚙️',
description: 'Any OpenAI-compatible endpoint',
apiUrl: '',
backendType: 'openai-compat',
requiresApiKey: false,
apiKeyHint: 'API Key (if required)',
models: [],
defaultModel: '',
},
};
class ProviderService {
constructor(storageManager) {
this.storageManager = storageManager;
this.configPath = path.join(os.homedir(), '.ag-x', 'ag-x', 'provider_config.json');
this.config = this.loadConfig();
}
loadConfig() {
try {
if (fs.existsSync(this.configPath)) {
const content = fs.readFileSync(this.configPath, 'utf-8');
return JSON.parse(content);
}
}
catch (e) {
console.error('Error loading provider config:', e);
}
// Build defaults from all predefined providers
const providers = {};
for (const [key, preset] of Object.entries(PREDEFINED_PROVIDERS)) {
providers[key] = {
...preset,
apiKey: '',
model: preset.defaultModel,
enabled: key === ProviderType.GOOGLE_GEMINI,
};
}
return {
activeProvider: ProviderType.GOOGLE_GEMINI,
providers,
};
}
saveConfig() {
try {
const dir = path.dirname(this.configPath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2), 'utf-8');
}
catch (e) {
console.error('Error saving provider config:', e);
}
}
getActiveProvider() {
return this.config.activeProvider;
}
setActiveProvider(providerType) {
this.config.activeProvider = providerType;
this.saveConfig();
}
getProviderConfig(providerType) {
return this.config.providers[providerType] || null;
}
updateProviderConfig(providerType, updates) {
if (this.config.providers[providerType]) {
Object.assign(this.config.providers[providerType], updates);
this.saveConfig();
}
}
getAllProviders() {
return this.config.providers;
}
getPredefinedProviders() {
return PREDEFINED_PROVIDERS;
}
getActiveProviderApiUrl() {
const provider = this.config.providers[this.config.activeProvider];
return provider?.apiUrl || 'https://daily-cloudcode-pa.sandbox.googleapis.com';
}
getActiveProviderApiKey() {
const provider = this.config.providers[this.config.activeProvider];
return provider?.apiKey || '';
}
getActiveProviderModel() {
const provider = this.config.providers[this.config.activeProvider];
return provider?.model || '';
}
getActiveBackendType() {
const provider = this.config.providers[this.config.activeProvider];
return provider?.backendType || 'gemini-native';
}
getActiveCcVersion() {
const provider = this.config.providers[this.config.activeProvider];
return provider?.ccVersion || '0.26.8';
}
/**
* Does this provider need the built-in translation proxy?
* gemini-native and native (OpenAI) go direct; everything else needs proxy.
*/
needsProxy() {
const bt = this.getActiveBackendType();
return bt !== 'gemini-native' && bt !== 'native';
}
/**
* Does this provider need the full translation proxy (anthropic, command-code)?
* command-code and anthropic need the full Python proxy for full compatibility.
*/
needsTranslateProxy() {
const bt = this.getActiveBackendType();
return bt === 'command-code' || bt === 'anthropic';
}
getProxyPort() {
return 9876;
}
}
exports.ProviderService = ProviderService;