Skip to content

Commit b9a6ac6

Browse files
authored
Create vial-mcp.js
1 parent a9cab9e commit b9a6ac6

File tree

1 file changed

+357
-0
lines changed

1 file changed

+357
-0
lines changed
Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
// Agent templates (simulating vial/agents/agent1.py to agent4.py)
2+
const agentTemplates = [
3+
`import torch
4+
import torch.nn as nn
5+
6+
class VialAgent1(nn.Module):
7+
def __init__(self):
8+
super().__init__()
9+
self.fc = nn.Linear(10, 1)
10+
def forward(self, x):
11+
return torch.sigmoid(self.fc(x))
12+
13+
model = VialAgent1()`,
14+
`import torch
15+
import torch.nn as nn
16+
17+
class VialAgent2(nn.Module):
18+
def __init__(self):
19+
super().__init__()
20+
self.fc = nn.Linear(20, 2)
21+
def forward(self, x):
22+
return torch.relu(self.fc(x))
23+
24+
model = VialAgent2()`,
25+
`import torch
26+
import torch.nn as nn
27+
28+
class VialAgent3(nn.Module):
29+
def __init__(self):
30+
super().__init__()
31+
self.fc = nn.Linear(15, 3)
32+
def forward(self, x):
33+
return torch.tanh(self.fc(x))
34+
35+
model = VialAgent3()`,
36+
`import torch
37+
import torch.nn as nn
38+
39+
class VialAgent4(nn.Module):
40+
def __init__(self):
41+
super().__init__()
42+
self.fc = nn.Linear(25, 4)
43+
def forward(self, x):
44+
return torch.softmax(self.fc(x), dim=1)
45+
46+
model = VialAgent4()`
47+
];
48+
49+
// Global state
50+
let logQueue = ['<p>Vial MCP Controller initialized. Use /help for API commands.</p>', '<p class="balance">$WEBXOS Balance: 0.0000 | Reputation: 0</p>'];
51+
let isAuthenticated = false;
52+
let isOffline = true;
53+
let masterKey = null;
54+
let walletKey = null;
55+
let agenticNetworkId = null;
56+
let tokenInterval = null;
57+
let reputation = 0;
58+
let blockchain = [];
59+
let apiCredentials = { key: null, secret: null };
60+
let vials = Array(4).fill().map((_, i) => ({
61+
id: `vial${i+1}`,
62+
status: 'stopped',
63+
code: agentTemplates[i],
64+
codeLength: agentTemplates[i].length,
65+
isPython: true,
66+
webxosHash: generateUUID(),
67+
wallet: { address: null, balance: 0, hash: null },
68+
tasks: [],
69+
quantumState: null,
70+
trainingData: [],
71+
config: {},
72+
isTraining: false,
73+
latency: 0
74+
}));
75+
let wallet = { address: null, balance: 0, hash: null };
76+
let lastLogMessage = null;
77+
let lastLogTime = 0;
78+
let lastLogId = 0;
79+
80+
// UUID generator
81+
function generateUUID() {
82+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
83+
const r = Math.random() * 16 | 0;
84+
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
85+
});
86+
}
87+
88+
// AES-256 encryption
89+
async function encryptData(data) {
90+
const key = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, ['encrypt']);
91+
const iv = crypto.getRandomValues(new Uint8Array(12));
92+
const encoded = new TextEncoder().encode(data);
93+
const encrypted = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, encoded);
94+
return { encrypted: Array.from(new Uint8Array(encrypted)), iv: Array.from(iv) };
95+
}
96+
97+
// SHA-256 hash
98+
async function sha256(data) {
99+
const encoded = new TextEncoder().encode(data);
100+
const hash = await crypto.subtle.digest('SHA-256', encoded);
101+
return Array.from(new Uint8Array(hash)).map(b => b.toString(16).padStart(2, '0')).join('');
102+
}
103+
104+
// Sanitize input
105+
function sanitizeInput(input) {
106+
return input.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
107+
.replace(/[<>{}]/g, '');
108+
}
109+
110+
// Validate .md format
111+
function validateMarkdown(mdContent) {
112+
if (!mdContent.includes('## Agentic Network') || mdContent.includes('<script')) {
113+
return false;
114+
}
115+
return true;
116+
}
117+
118+
// Parse .md for training data
119+
function parseMarkdownForTraining(mdContent) {
120+
const lines = mdContent.split('\n');
121+
let tasks = [];
122+
let parameters = {};
123+
let inTaskSection = false;
124+
for (let line of lines) {
125+
if (line.startsWith('## Tasks')) {
126+
inTaskSection = true;
127+
} else if (inTaskSection && line.startsWith('- ')) {
128+
tasks.push(line.slice(2).trim());
129+
} else if (line.match(/^- Parameter: (\w+): (.+)/)) {
130+
const [, key, value] = line.match(/^- Parameter: (\w+): (.+)/);
131+
parameters[key] = value;
132+
}
133+
}
134+
return { tasks, parameters };
135+
}
136+
137+
// Simulate blockchain transaction
138+
async function addToBlockchain(type, data) {
139+
if (isOffline && type !== 'train' && type !== 'import' && type !== 'export') {
140+
return null; // Skip blockchain in offline mode for non-training actions
141+
}
142+
const timestamp = new Date().toISOString();
143+
const prevHash = blockchain.length ? blockchain[blockchain.length - 1].hash : '0'.repeat(64);
144+
const hash = await sha256(`${type}${JSON.stringify(data, null, 0)}${timestamp}${prevHash}`);
145+
const block = { type, data, timestamp, prevHash, hash };
146+
blockchain.push(block);
147+
return hash;
148+
}
149+
150+
// Debounce utility
151+
function debounce(func, wait) {
152+
let timeout;
153+
return (...args) => {
154+
clearTimeout(timeout);
155+
timeout = setTimeout(() => func(...args), wait);
156+
};
157+
}
158+
159+
// Log event with deduplication
160+
function logEvent(event_type, message, metadata = {}) {
161+
const timestamp = new Date().toISOString();
162+
const now = Date.now();
163+
const logId = ++lastLogId;
164+
const baseMessage = message.replace(/^\[\S+\]\s*|\s*\[ID:\d+\]$/, '').trim();
165+
if (baseMessage === lastLogMessage && (now - lastLogTime) < 300) return;
166+
lastLogMessage = baseMessage;
167+
lastLogTime = now;
168+
const formattedMessage = `[${timestamp}] ${message} [ID:${logId}]`;
169+
logQueue.push(`<p class="${event_type === 'error' ? 'error' : 'command'}">${formattedMessage}</p>`);
170+
if (logQueue.length > 50) logQueue.shift();
171+
debouncedUpdateConsole();
172+
console.log(`${event_type}: ${message}`, metadata);
173+
}
174+
175+
// Error notification
176+
function showErrorNotification(message) {
177+
const errorNotification = document.getElementById('error-notification');
178+
if (errorNotification) {
179+
errorNotification.textContent = message;
180+
errorNotification.classList.add('visible');
181+
setTimeout(() => errorNotification.classList.remove('visible'), 5000);
182+
} else {
183+
console.error(`Notification: ${message}`);
184+
}
185+
}
186+
187+
// Update console
188+
const debouncedUpdateConsole = debounce(() => {
189+
const consoleDiv = document.getElementById('console');
190+
if (consoleDiv) {
191+
consoleDiv.innerHTML = logQueue.join('');
192+
consoleDiv.scrollTop = consoleDiv.scrollHeight;
193+
}
194+
}, 100);
195+
196+
// Update vial status bars
197+
function updateVialStatusBars() {
198+
const vialStatusBars = document.getElementById('vial-status-bars');
199+
if (!vialStatusBars) return;
200+
vials.forEach(vial => {
201+
vial.latency = isOffline ? 0 : Math.floor(Math.random() * (200 - 50 + 1)) + 50;
202+
});
203+
vialStatusBars.innerHTML = vials.map(vial => {
204+
const mode = vial.isTraining ? 'Training' : (isOffline ? 'Offline (Wallet Disabled)' : 'Online');
205+
const statusClass = vial.isTraining ? 'training' : (isOffline ? 'offline-grey' : 'online');
206+
const fillClass = vial.status === 'running' ? statusClass : '';
207+
return `
208+
<div class="progress-container">
209+
<span class="progress-label">${vial.id}</span>
210+
<div class="progress-bar">
211+
<div class="progress-fill ${fillClass}" style="width: ${vial.status === 'running' ? '100%' : '0%'};"></div>
212+
</div>
213+
<span class="status-text ${statusClass}">Latency: ${vial.latency}ms | Size: ${vial.codeLength} bytes | Mode: ${mode}</span>
214+
</div>
215+
`;
216+
}).join('');
217+
}
218+
219+
// Update balance and reputation display
220+
function updateBalanceDisplay() {
221+
const balanceIndex = logQueue.findIndex(log => log.includes('$WEBXOS Balance'));
222+
const displayBalance = isOffline ? 'N/A (Offline)' : wallet.balance.toFixed(4);
223+
const displayReputation = isOffline ? 'N/A (Offline)' : reputation;
224+
if (balanceIndex !== -1) {
225+
logQueue[balanceIndex] = `<p class="balance">$WEBXOS Balance: ${displayBalance} | Reputation: ${displayReputation}</p>`;
226+
} else {
227+
logQueue.push(`<p class="balance">$WEBXOS Balance: ${displayBalance} | Reputation: ${displayReputation}</p>`);
228+
}
229+
if (logQueue.length > 50) logQueue.shift();
230+
debouncedUpdateConsole();
231+
}
232+
233+
// Earn tokens and reputation
234+
async function startTokenEarning() {
235+
if (tokenInterval) clearInterval(tokenInterval);
236+
if (isOffline) {
237+
logEvent('error', '$WEBXOS earning disabled in offline mode. Switch to online mode to earn tokens.', {});
238+
return;
239+
}
240+
tokenInterval = setInterval(async () => {
241+
if (!isAuthenticated || isOffline) {
242+
clearInterval(tokenInterval);
243+
disableFunctions();
244+
logEvent('error', 'Authentication lost or offline: $WEBXOS earning stopped.', {});
245+
return;
246+
}
247+
wallet.balance += 1;
248+
reputation += 1;
249+
const blockHash = await addToBlockchain('token_earn', { wallet: wallet.address, amount: 1, reputation });
250+
vials.forEach(vial => {
251+
vial.wallet.balance = wallet.balance / 4;
252+
vial.wallet.hash = blockHash;
253+
});
254+
wallet.hash = blockHash;
255+
logEvent('token', `Earned 1 $WEBXOS | Reputation: ${reputation} | Block: ${blockHash.slice(0, 8)}...`, { wallet: wallet.address });
256+
logEvent('token', `Earned 1 $WEBXOS | Reputation: ${reputation} | Block: ${blockHash.slice(0, 8)}...`, { wallet: wallet.address });
257+
updateBalanceDisplay();
258+
}, 10000);
259+
}
260+
261+
// Disable functions on auth loss or offline mode
262+
function disableFunctions() {
263+
const buttons = ['quantumLinkButton', 'exportButton', 'importButton'];
264+
if (isOffline) buttons.push('apiAccessButton');
265+
buttons.forEach(id => {
266+
const btn = document.getElementById(id);
267+
if (btn) btn.disabled = true;
268+
});
269+
const authButton = document.getElementById('authButton');
270+
if (authButton) authButton.classList.remove('active-monitor');
271+
if (isOffline) {
272+
clearInterval(tokenInterval);
273+
apiCredentials = { key: null, secret: null };
274+
logEvent('system', 'Offline mode: $WEBXOS earning and API access disabled.', {});
275+
updateVialStatusBars();
276+
}
277+
}
278+
279+
// Authenticate
280+
async function authenticate() {
281+
const isOnline = confirm('Authenticate in online mode? Cancel for offline mode.');
282+
isOffline = !isOnline;
283+
agenticNetworkId = generateUUID();
284+
masterKey = isOffline ? 'offline' : 'online';
285+
walletKey = isOffline ? null : generateUUID();
286+
wallet = { address: isOffline ? null : generateUUID(), balance: 0, hash: isOffline ? null : await sha256(agenticNetworkId) };
287+
reputation = 0;
288+
blockchain = [];
289+
apiCredentials = { key: null, secret: null };
290+
isAuthenticated = true;
291+
await addToBlockchain('auth', { wallet: wallet.address, networkId: agenticNetworkId });
292+
vials.forEach((vial, i) => {
293+
vial.wallet = { address: isOffline ? null : generateUUID(), balance: 0, hash: wallet.hash };
294+
vial.quantumState = { qubits: [], entanglement: 'initialized' };
295+
});
296+
const authButton = document.getElementById('authButton');
297+
if (authButton) authButton.classList.add('active-monitor');
298+
['quantumLinkButton', 'exportButton', 'importButton'].forEach(id => {
299+
const btn = document.getElementById(id);
300+
if (btn) btn.disabled = false;
301+
});
302+
if (!isOffline) {
303+
const apiAccessButton = document.getElementById('apiAccessButton');
304+
if (apiAccessButton) apiAccessButton.disabled = false;
305+
}
306+
logEvent('auth', `Authentication successful (${isOffline ? 'offline' : 'online'} mode). Quantum network allocated. Use /help for API commands.`, { networkId: agenticNetworkId });
307+
startTokenEarning();
308+
updateVialStatusBars();
309+
updateBalanceDisplay();
310+
}
311+
312+
// Initialize
313+
document.addEventListener('DOMContentLoaded', () => {
314+
updateVialStatusBars();
315+
updateBalanceDisplay();
316+
const elements = {
317+
authButton: document.getElementById('authButton'),
318+
voidButton: document.getElementById('voidButton'),
319+
troubleshootButton: document.getElementById('troubleshootButton'),
320+
quantumLinkButton: document.getElementById('quantumLinkButton'),
321+
exportButton: document.getElementById('exportButton'),
322+
importButton: document.getElementById('importButton'),
323+
apiAccessButton: document.getElementById('apiAccessButton'),
324+
apiSubmit: document.getElementById('api-generate'),
325+
apiClose: document.getElementById('api-close'),
326+
fileInput: document.getElementById('file-input'),
327+
promptInput: document.getElementById('prompt-input')
328+
};
329+
330+
elements.authButton.addEventListener('click', authenticate);
331+
elements.voidButton.addEventListener('click', voidVials);
332+
elements.troubleshootButton.addEventListener('click', troubleshoot);
333+
elements.quantumLinkButton.addEventListener('click', quantumLink);
334+
elements.exportButton.addEventListener('click', exportVials);
335+
elements.importButton.addEventListener('click', () => elements.fileInput.click());
336+
elements.apiAccessButton.addEventListener('click', showApiPopup);
337+
elements.apiSubmit.addEventListener('click', generateApiCredentials);
338+
elements.apiClose.addEventListener('click', () => {
339+
const apiPopup = document.getElementById('api-popup');
340+
if (apiPopup) apiPopup.classList.remove('visible');
341+
});
342+
elements.fileInput.addEventListener('change', importFile);
343+
elements.promptInput.addEventListener('keydown', e => {
344+
if (e.key === 'Enter' && !e.shiftKey) {
345+
e.preventDefault();
346+
if (elements.promptInput.value.trim()) {
347+
handleGitCommand(elements.promptInput.value);
348+
elements.promptInput.value = '';
349+
}
350+
}
351+
});
352+
353+
logEvent('system', 'Vial MCP Controller initialized. Use /help for API commands.', {});
354+
}, { once: true });
355+
</script>
356+
</body>
357+
</html>

0 commit comments

Comments
 (0)