Files
ag-x/dist/services/apiProxy.js
admin b3c7be44e6 fix: Provider sync on every startup + sandbox fixes (v2.0.4)
Critical fixes:
- ALWAYS sync active AG X provider to endpoints.json on startup
  (previously only synced on first run, causing LS to use stale data)
- Add --no-sandbox to proxy process spawns (fixes SIGTRAP crash on Linux)
- Add --no-sandbox for all Electron modes (not just headless)
- Add --ag-reset flag to re-trigger welcome screen
- Bump version to 2.0.4

Root causes fixed:
1. endpoints.json was never updated after first-run, so LS used wrong provider
2. Electron child processes (translation proxy) crashed due to SUID sandbox
3. No way to re-show provider selection after initial setup
2026-05-23 00:23:46 +04:00

117 lines
4.4 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ApiProxy = void 0;
const http = require("http");
const https = require("https");
const child_process = require("child_process");
const path = require("path");
const os = require("os");
const fs = require("fs");
const translationProxy_1 = require("./translationProxy");
/**
* API Proxy for AG X.
*
* All backends now use the built-in Node.js translation proxy.
* No external Python or tools required.
*/
class ApiProxy {
constructor(providerService) {
this.providerService = providerService;
this.server = null;
this.proxyProcess = null;
this.port = providerService.getProxyPort();
}
start() {
if (this.server || this.proxyProcess) {
return;
}
const backendType = this.providerService.getActiveBackendType();
if (backendType === 'gemini-native' || backendType === 'native') {
console.log('[ApiProxy] Native backend, no proxy needed');
return;
}
this.startInternalProxy();
}
/**
* Start the built-in Node.js translation proxy as a child process
*/
startInternalProxy() {
const activeProvider = this.providerService.getActiveProvider();
const config = this.providerService.getProviderConfig(activeProvider);
if (!config) {
console.error('[ApiProxy] No provider config found');
return;
}
// Prepare the proxy config
const configDir = path.join(os.homedir(), '.cache', 'ag-x-proxy');
if (!fs.existsSync(configDir)) {
fs.mkdirSync(configDir, { recursive: true });
}
const models = (config.models || []).map((m) => {
if (typeof m === 'string') {
return { id: m, object: "model", created: 1700000000, owned_by: activeProvider };
}
return m;
});
const proxyConfig = {
port: this.port,
backend_type: config.backendType || 'openai-compat',
target_url: config.apiUrl || '',
api_key: config.apiKey || '',
cc_version: config.ccVersion || '0.26.8',
oauth_provider: config.oauthProvider || '',
reasoning_enabled: config.reasoningEnabled !== undefined ? config.reasoningEnabled : true,
reasoning_effort: config.reasoningEffort || 'medium',
models: models,
};
const configPath = path.join(configDir, `ag-x-proxy-${this.port}.json`);
fs.writeFileSync(configPath, JSON.stringify(proxyConfig, null, 2), 'utf-8');
console.log(`[ApiProxy] Starting built-in Node.js translation proxy on port ${this.port}`);
// Use Electron's Node.js binary to run our translation proxy
const proxyScript = path.join(__dirname, 'translationProxy.js');
const nodeBin = process.execPath;
this.proxyProcess = child_process.spawn(nodeBin, ['--no-sandbox', proxyScript], {
stdio: ['ignore', 'pipe', 'pipe'],
detached: false,
env: { ...process.env },
});
this.proxyProcess.stdout?.on('data', (data) => {
const lines = data.toString().trim().split('\n');
for (const line of lines) {
console.log(`[Proxy] ${line}`);
}
});
this.proxyProcess.stderr?.on('data', (data) => {
const lines = data.toString().trim().split('\n');
for (const line of lines) {
console.log(`[Proxy] ${line}`);
}
});
this.proxyProcess.on('error', (err) => {
console.error('[ApiProxy] Proxy error:', err);
});
this.proxyProcess.on('exit', (code, signal) => {
console.log(`[ApiProxy] Proxy exited with code ${code}, signal ${signal}`);
this.proxyProcess = null;
});
this.proxyProcess.unref();
console.log(`[ApiProxy] Built-in Node.js proxy spawned for ${config.backendType} on port ${this.port}`);
}
stop() {
if (this.proxyProcess) {
try {
this.proxyProcess.kill();
}
catch (e) { /* ignore */ }
this.proxyProcess = null;
}
if (this.server) {
this.server.close();
this.server = null;
console.log('[ApiProxy] Stopped');
}
}
}
exports.ApiProxy = ApiProxy;