@@ -413,9 +419,9 @@ function getChatJS() {
function addUser(t){const d=document.createElement('div');d.style.cssText='align-self:flex-end;max-width:75%;background:linear-gradient(135deg,rgba(34,197,94,.15),rgba(6,182,212,.1));border:1px solid rgba(34,197,94,.2);border-radius:12px 12px 2px 12px;padding:10px 14px;';d.innerHTML='
YOU
'+esc(t)+'
';msgArea.appendChild(d);scroll();}
function md(s){if(!s)return '';var bt=String.fromCharCode(96);s=s.replace(new RegExp(bt+bt+bt+'([\\\\s\\\\S]*?)'+bt+bt+bt,'g'),function(_,c){return '
'+esc(c.trim())+'
';});s=s.replace(new RegExp(bt+'([^'+bt+']+)'+bt,'g'),'
$1');s=s.replace(/^### (.+)$/gm,'
$1
');s=s.replace(/^## (.+)$/gm,'
$1
');s=s.replace(/^# (.+)$/gm,'
$1
');s=s.replace(/\\*\\*(.+?)\\*\\*/g,'
$1');s=s.replace(/\\*(.+?)\\*/g,'
$1');s=s.replace(/^- (.+)$/gm,'
• $1
');s=s.replace(/\\n/g,'
');return s;}
function addSystem(t){const d=document.createElement('div');d.style.cssText='text-align:center;font-size:10px;color:#444;padding:4px;';d.textContent=t;msgArea.appendChild(d);scroll();}
- function addAI(c,m,ms){const colors={claude:'#a78bfa',chatgpt:'#22c55e',gemini:'#3b82f6',perplexity:'#f97316',auto:'#06b6d4'};const cl=colors[m]||'#22c55e';const d=document.createElement('div');d.style.cssText='align-self:flex-start;max-width:85%;background:rgba(16,16,24,.8);border:1px solid rgba(255,255,255,.06);border-radius:12px 12px 12px 2px;padding:10px 14px;';d.innerHTML='
'+(m||'AI').toUpperCase()+''+(ms?(ms/1000).toFixed(1)+'s':'')+'
'+md(c)+'
';msgArea.appendChild(d);scroll();}
- function addBattleGrid(providers){var colors={claude:'#a78bfa',chatgpt:'#22c55e',gemini:'#3b82f6',perplexity:'#f97316'};var cols=providers.length<=2?'1fr 1fr':providers.length===3?'1fr 1fr 1fr':'1fr 1fr';var d=document.createElement('div');d.id='battle-grid-'+battleId;d.style.cssText='display:grid;grid-template-columns:'+cols+';gap:8px;width:100%;';providers.forEach(function(p){var cell=document.createElement('div');cell.id='battle-cell-'+p+'-'+battleId;cell.style.cssText='background:rgba(16,16,24,.8);border:1px solid rgba(255,255,255,.06);border-radius:10px;padding:10px;min-height:80px;';var cl=colors[p]||'#22c55e';cell.innerHTML='
'+p+'
Waiting...
';d.appendChild(cell);});msgArea.appendChild(d);scroll();}
- function addBattleResponse(c,m,ms){var cell=document.getElementById('battle-cell-'+m+'-'+battleId);if(cell){var cl={claude:'#a78bfa',chatgpt:'#22c55e',gemini:'#3b82f6',perplexity:'#f97316'}[m]||'#22c55e';cell.innerHTML='
'+m+''+(ms?(ms/1000).toFixed(1)+'s':'')+'
'+md(c)+'
';cell.style.borderColor='rgba(255,255,255,.1)';scroll();}else{addAI(c,m,ms);}}
+ function addAI(c,m,ms){const colors={claude:'#a78bfa',chatgpt:'#22c55e',gemini:'#3b82f6',perplexity:'#f97316',zai:'#3b6cf6',auto:'#06b6d4'};const cl=colors[m]||'#22c55e';const d=document.createElement('div');d.style.cssText='align-self:flex-start;max-width:85%;background:rgba(16,16,24,.8);border:1px solid rgba(255,255,255,.06);border-radius:12px 12px 12px 2px;padding:10px 14px;';d.innerHTML='
'+(m||'AI').toUpperCase()+''+(ms?(ms/1000).toFixed(1)+'s':'')+'
'+md(c)+'
';msgArea.appendChild(d);scroll();}
+ function addBattleGrid(providers){var colors={claude:'#a78bfa',chatgpt:'#22c55e',gemini:'#3b82f6',perplexity:'#f97316',zai:'#3b6cf6'};var cols=providers.length<=2?'1fr 1fr':providers.length===3?'1fr 1fr 1fr':'1fr 1fr';var d=document.createElement('div');d.id='battle-grid-'+battleId;d.style.cssText='display:grid;grid-template-columns:'+cols+';gap:8px;width:100%;';providers.forEach(function(p){var cell=document.createElement('div');cell.id='battle-cell-'+p+'-'+battleId;cell.style.cssText='background:rgba(16,16,24,.8);border:1px solid rgba(255,255,255,.06);border-radius:10px;padding:10px;min-height:80px;';var cl=colors[p]||'#22c55e';cell.innerHTML='
'+p+'
Waiting...
';d.appendChild(cell);});msgArea.appendChild(d);scroll();}
+ function addBattleResponse(c,m,ms){var cell=document.getElementById('battle-cell-'+m+'-'+battleId);if(cell){var cl={claude:'#a78bfa',chatgpt:'#22c55e',gemini:'#3b82f6',perplexity:'#f97316',zai:'#3b6cf6'}[m]||'#22c55e';cell.innerHTML='
'+m+''+(ms?(ms/1000).toFixed(1)+'s':'')+'
'+md(c)+'
';cell.style.borderColor='rgba(255,255,255,.1)';scroll();}else{addAI(c,m,ms);}}
function addError(t){const d=document.createElement('div');d.style.cssText='align-self:flex-start;max-width:80%;background:rgba(239,68,68,.08);border:1px solid rgba(239,68,68,.15);border-radius:8px;padding:8px 12px;';d.innerHTML='
⚠ '+esc(t)+'';msgArea.appendChild(d);scroll();}
function updateStatus(m){removeTyping();const d=document.createElement('div');d.className='typing-indicator';d.style.cssText='align-self:flex-start;font-size:10px;color:#22c55e;padding:6px 12px;background:rgba(34,197,94,.05);border-radius:8px;display:flex;align-items:center;gap:6px;';d.innerHTML='
'+(m.status||'processing')+'...';msgArea.appendChild(d);scroll();}
function removeTyping(){msgArea.querySelectorAll('.typing-indicator').forEach(e=>e.remove());}
@@ -492,7 +498,7 @@ function getDocsPage() {
⚡ Proxima API
Unified AI Gateway · Port ${REST_PORT} · v${VERSION}
- ${['perplexity', 'chatgpt', 'claude', 'gemini'].map(p =>
+ ${['perplexity', 'chatgpt', 'claude', 'gemini', 'zai'].map(p =>
`
${p[0].toUpperCase() + p.slice(1)}
`
).join('')}
@@ -541,6 +547,7 @@ POST /v1/chat/completions
claude · sonnet · anthropic
gemini · google · bard
perplexity · pplx · sonar
+
zai · glm · glm-5.2 · z.ai
auto → best available
@@ -1277,7 +1284,7 @@ End with a security score (0-100).`;
aliases: Object.entries(MODEL_ALIASES).filter(([_, v]) => v === p).map(([k]) => k).filter(k => k !== p)
}));
// Also show disabled ones
- const allProviders = ['chatgpt', 'claude', 'gemini', 'perplexity'];
+ const allProviders = ['chatgpt', 'claude', 'gemini', 'perplexity', 'zai'];
allProviders.filter(p => !enabled.includes(p)).forEach(p => {
models.push({
id: p, object: 'model', owned_by: 'proxima', status: 'disabled',
diff --git a/electron/ws-server.cjs b/electron/ws-server.cjs
index c8714cb..688a03f 100644
--- a/electron/ws-server.cjs
+++ b/electron/ws-server.cjs
@@ -152,7 +152,7 @@ function pickBestProvider(preferred) {
if (found) return found;
return null;
}
- return ['claude', 'chatgpt', 'gemini', 'perplexity'].find(p => enabled.includes(p)) || null;
+ return ['claude', 'chatgpt', 'gemini', 'perplexity', 'zai'].find(p => enabled.includes(p)) || null;
}
// ─── Message Handler ────────────────────────────────
diff --git a/src/mcp-server-v3.js b/src/mcp-server-v3.js
index 30733f7..8dd12cd 100644
--- a/src/mcp-server-v3.js
+++ b/src/mcp-server-v3.js
@@ -411,7 +411,7 @@ class SmartRouter {
async smartQuery(message, preferredProvider = null) {
const enabled = getEnabledProviders();
- const order = ['chatgpt', 'claude', 'perplexity', 'gemini'];
+ const order = ['chatgpt', 'claude', 'perplexity', 'gemini', 'zai'];
// Start with preferred if enabled
if (preferredProvider && enabled.has(preferredProvider)) {
@@ -462,8 +462,9 @@ const perplexity = new AIProvider('perplexity', ipcClient);
const chatgpt = new AIProvider('chatgpt', ipcClient);
const claude = new AIProvider('claude', ipcClient);
const gemini = new AIProvider('gemini', ipcClient);
+const zai = new AIProvider('zai', ipcClient);
-const router = new SmartRouter({ perplexity, chatgpt, claude, gemini });
+const router = new SmartRouter({ perplexity, chatgpt, claude, gemini, zai });
// Create MCP Server
const server = new McpServer({
@@ -1110,6 +1111,24 @@ server.tool(
}
);
+server.tool(
+ 'ask_glm',
+ {
+ message: z.string().describe('Message to send to GLM-5.2 (z.ai)'),
+ files: z.array(z.string()).optional().describe('Optional: file paths to include as context. Supports line ranges like "path/file.js:10-50". For large files, always specify relevant line ranges only.')
+ },
+ async ({ message, files }) => {
+ const disabled = checkDisabled('zai');
+ if (disabled) return disabled;
+ try {
+ const fullMessage = buildMessageWithFiles(message, files);
+ return toolResponse(await zai.chat(fullMessage));
+ } catch (err) {
+ return toolError(err);
+ }
+ }
+);
+
server.tool(
'ask_all_ais',
{